2013-10-07 3 views
1

Наблюдения в моем наборе данных содержат историю ходов для каждого игрока. Я хотел бы подсчитать количество последовательных серий ходов некоторой заранее определенной длины (2, 3 и более 3 ходов) в первой и второй половинах игры. Последовательности не могут перекрываться, т.е. последовательность 1111 следует рассматривать как последовательность длины 4, а не 2 последовательности длиной 2. То есть, для наблюдения, например так:Stata: подсчет числа последовательных вхождений заданной длины

+-------+-------+-------+-------+-------+-------+-------+-------+ 
| Move1 | Move2 | Move3 | Move4 | Move5 | Move6 | Move7 | Move8 | 
+-------+-------+-------+-------+-------+-------+-------+-------+ 
|  1 |  1 |  1 |  1 | .  | .  |  1 |  1 | 
+-------+-------+-------+-------+-------+-------+-------+-------+ 

... следующие переменные должны быть сформированы :

Number of sequences of 2 in the first half =0 
Number of sequences of 2 in the second half =1 
Number of sequences of 3 in the first half =0 
Number of sequences of 3 in the second half =0 
Number of sequences of >3 in the first half =1 
Number of sequences of >3 in the second half = 0 

у меня есть два возможных варианты того, как приступить к этой задаче, но ни один из этих приводит к окончательному решению:

Вариант 1: Уточняя тактическое предложение Ники использовать строки (Stata: Maximum number of consecutive occurrences of the same value across variables), я иметь конкатена Ted все «MOVE *» переменные и попытался определить начальную позицию подстроки:

egen test1 = concat(move*) 
gen test2 = subinstr(test1,"11","X",.) // find all consecutive series of length 2 

Есть несколько проблем с Вариантом 1: (1) он не учитывает случаи с перекрытием последовательностей («1111» распознается как 2 последовательности из 2) (2) он сокращает итоговый тест строки2, так что положения X больше не соответствуют начальным позициям в test1 (3), он не учитывает переменную длину подстроки, если Мне нужно проверить последовательности длиной больше 3.

Вариант 2. Создайте вспомогательный набор переменных, чтобы идентифицировать начальные позиции последовательного набора (наборов) из 1s некоторой фиксированной предопределенной длины. Основываясь на более раннем примере, чтобы подсчитать последовательности длины 2, я пытаюсь получить вспомогательный набор переменных, который будет равен 1, если последовательность начинается с данного перемещения, а в противном случае - ноль:

+-------+-------+-------+-------+-------+-------+-------+-------+ 
| Move1 | Move2 | Move3 | Move4 | Move5 | Move6 | Move7 | Move8 | 
+-------+-------+-------+-------+-------+-------+-------+-------+ 
|  0 |  0 |  0 |  0 |  0 |  0 |  1 |  0 | 
+-------+-------+-------+-------+-------+-------+-------+-------+ 

Мой код выглядит следующим образом, но он ломается, когда я пытаюсь перезапустить подсчет последовательных вхождений:

quietly forval i = 1/42 { 
gen temprow`i' =. 
egen rowsum = rownonmiss(seq1-seq`i') //count number of occurrences 
replace temprow`i'=rowsum 
mvdecode seq1-seq`i',mv(1) if rowsum==2 
drop rowsum 
} 

кто-нибудь знает способ решения этой задачи?

ответ

1

Предположим, что строковая переменная, конкатенирующая все ходы all (название test1 вряд ли вызывает воспоминания).

ПЕРВЫЙ TRY: отрывая ПРИМЕР БУКВАЛЬНО

Из вашего примера с 8 ходов, первая половина игры движется 1-4 и вторая половина движется 5-8. Таким образом, для каждой половины есть только один способ иметь> 3 хода, а именно, что есть 4 хода. В этом случае каждая подстрока будет "1111" и подсчет сводится к тестированию на одной возможности:

gen count_1_4 = substr(all, 1, 4) == "1111" 
gen count_2_4 = substr(all, 5, 4) == "1111" 

Расширение этого подхода, существуют только два способа, чтобы иметь 3 движется в последовательности:

gen count_1_3 = inlist(substr(all, 1, 4), "111.", ".111") 
gen count_2_3 = inlist(substr(all, 5, 4), "111.", ".111") 

В подобных стиль, в каждой половине игры не может быть двух экземпляров из 2 ходов, так как это будет соответствовать 4 ходам. Таким образом, не более одного экземпляра из двух ходов последовательно в каждой половине.Этот экземпляр должен соответствовать любому из двух шаблонов: "11." или ".11". ".11." разрешено, поэтому оба включают оба. Мы также должны исключить любое ложное совпадение с последовательностью из трех ходов, как только что упомянуто.

gen count_1_2 = (strpos(substr(all, 1, 4), "11.") | strpos(substr(all, 1, 4), ".11")) & !count_1_3 
gen count_2_2 = (strpos(substr(all, 5, 4), "11.") | strpos(substr(all, 5, 4), ".11")) & !count_2_3 

Результат каждого strpos() оценки будет положительным, если совпадение найдено, и (арг1 | арг2) будет верно (1), если один из аргументов является положительным. (Для Stata ненулевое значение истинно в логических оценках.)

Это очень похоже на вашу конкретную проблему, но не намного хуже для этого.

P.S. Я не пытался понять ваш код. Кажется, вы сбиваете с толку subinstr() с strpos(). Если вы хотите знать позиции, subinstr() не может помочь.

ВТОРОЙ TRY

Ваш последний сегмент кода означает, что ваш пример достаточно ввести в заблуждение: если может быть 42 ходов, выше подход не может быть продлен без боли. Вам нужен другой подход.

Предположим, что строковая переменная all может содержать до 42 символов. Я отброшу различие между первой и второй половинами, что можно решить, изменив этот подход. В самом простом случае просто разделите историю на две переменные: одну для первой половины, вторую - вторую и повторите дважды.

Вы можете клонировать историю,

clonevar work = all 
    gen length1 = . 
    gen length2 = . 

и настроить count переменные. Здесь count_4 будет содержать кол-во 4 или более.

gen count_4 = 0 
    gen count_3 = 0 
    gen count_2 = 0 

Сначала мы ищем ход последовательности длины 42, ..., 2. Каждый раз, когда мы находим один, мы его пустой и ударяться счетом.

qui forval j = 42(-1)2 { 
     replace length1 = length(work) 
     local pattern : di _dup(`j') "1" 
     replace work = subinstr(work, "`pattern'", "", .) 
     replace length2 = length(work) 
     if `j' >= 4 { 
      replace count4 = count4 + (length1 - length2)/`j' 
     } 
     else if `j' == 3 { 
      replace count3 = count3 + (length1 - length2)/3 
     } 
     else if `j' == 2 { 
      replace count2 = count2 + (length1 - length2)/2 
     } 
    } 

Важные детали здесь

  1. Если удалить (повторяющиеся экземпляры) образец и измерить изменение длины, мы только что удалили (изменение длины)/(длина шаблона) экземпляров этого шаблона. Итак, если я ищу «11» и обнаружил, что длина уменьшилась на 4, я просто нашел два экземпляра.

  2. Работа вниз и удаление найденного нами гарантируют, что мы не находим ложных срабатываний, например. если «1111111» удален, мы не находим более поздних «111111», «11111», ..., «11», которые включены в него.

  3. Исключение означает, что мы должны работать над клоном, чтобы не разрушать то, что представляет интерес.

+0

Уважаемый Ник, большое вам спасибо, это прекрасно работает, если мы рассмотрим всю последовательность! Однако, если я попытаюсь разбить последовательность на 2 части, она не будет работать для длинных прогонов в 1 с, начиная с конца первой половины. Например, 0001111100 будет сообщать count2_1 = 1 и count3_2 = 1, в то время как оно должно быть count4_1 = 1 ... Это моя вина, что я не указал это в своем вопросе изначально.Вот почему моя идея заключалась в том, что для каждой последовательности идентифицируйте начальные позиции последовательных прогонов и подсчитайте те, которые попадают в 1 и 2 половинки. И я спотыкаюсь о том, чтобы идентифицировать эти стартовые позиции. – user2700264

+1

Чем сложнее вопрос, тем больше вам нужно учитывать мои стратегические рекомендации по реструктуризации данных панели. Тогда отслеживание начальных позиций, а также длительности заклинаний тривиально. См. Снова http://stackoverflow.com/questions/18576167/stata-maximum-number-of-consecutive-occurrences-of-the-same-value-across-variab –

+0

Вы были абсолютно правы, комбинация reshape и tsset работала в совершенстве! Еще раз спасибо, должен был последовать за вашим советом гораздо раньше. – user2700264

Смежные вопросы