Заменить подмножество данных последовательностью целых чисел

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

id    test
1     A
2     A
3     A
.     B
.     B
.     B

Я хотел бы заполнить пропущенные значения последовательностью целых чисел, соответствующих их id:

id    test
1     A
2     A
3     A
1     B
2     B
3     B

Сначала я думал об использовании цикла forvalues следующим образом:

forvalues i=1/3 {
    replace id = `i' if (id == .)
}

Но это (по понятным причинам) просто заменяет все отсутствующие значения на 1 во время первой итерации.

Затем я подумал об ограничении цикла подмножеством данных с помощью индексации строк (как в R), но эта функция, похоже, не существует для Stata(?):

forvalues i=1/3 {
   replace id[3+`i'] = `i' if (id == .)
}

Как я могу выполнить эту, казалось бы, простую задачу в Stata?


person ageil    schedule 05.09.2015    source источник
comment
Это очень скудное описание предположений, связанных с вашими данными. Всегда ли есть 3 идентификатора на тест? Сгруппированы ли отдельные значения теста вместе или есть несколько наборов наблюдений с одним и тем же значением теста? Есть ли другая переменная, которая определяет, в каком порядке появляются 3 (или что-то еще) наблюдения для одного и того же значения теста? Вы уверены, что отсутствующие значения id являются «все или ничего», что не существует значения test, для которого отсутствует только 1 из 3 (или любых других) значений id?   -  person    schedule 05.09.2015


Ответы (5)


Хорошо, подумав еще немного, я думаю, что решил свою проблему. Самое простое решение использует _n-функцию Stata, не прибегая к циклам:

replace id = _n - 3 if (id == .)

Кажется, это помогает.

person ageil    schedule 05.09.2015
comment
Это работает, если у вас есть только 6 наблюдений. Если вы хотите, чтобы идентификаторы повторяли 1, 2, 3, то это не сработает. - person Nick Cox; 05.09.2015
comment
И если у вас есть только 6 наблюдений, с помощью редактора данных Stata вы можете заменить отсутствующие значения вручную. :-) - person ; 05.09.2015

Одна из различных возможностей (для повторения идентификаторов 1, 2, 3, 1, 2, 3,..., как я прочитал вопрос)

replace id = 1 + mod(_n - 1, 3) if missing(id) 

или проверьте help egen для seq() функции.

egen newid = seq(), to(3) 
replace id = newid if missing(id) 

Учитывая исходные 1, 2, 3 в первых трех наблюдениях, тогда

replace id = id[_n-3] if missing(id) 

также будет работать.

person Nick Cox    schedule 05.09.2015

Или, возможно,

replace id = cond(test==test[_n-1],id[_n-1]+1,1) if missing(id)

что не требует наличия ровно трех идентификаторов для каждого теста.

person Community    schedule 05.09.2015

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

sort test id
by test: gen id2 = _n
replace id = id2 if missing(id)

Обратите внимание, что вы должны изменить первую сортировку по мере необходимости. По характеру вашего вопроса нет никакого смысла в том, чтобы порядок элементов с test == B был «упорядочен», поэтому вы должны убедиться, что первоначальная сортировка помещает их в желаемый порядок.

РЕДАКТИРОВАТЬ: Как заметил Ник Кокс, этот код сводится к одному вкладышу, что предпочтительнее, если это желаемое действие. Я записал его в 3 строки для простоты, а также чтобы отметить следующие факты:

  1. Сортировка должна учитываться независимо от того, делаете ли вы это самостоятельно или в команде bysort, чтобы метки соответствовали цели программиста.

  2. Если вы хотите выборочно сравнить новые идентификаторы со старыми, может быть полезно иметь возможность визуально видеть id2, просто чтобы убедиться, что код работает.

Как только оба из них будут уверены, я согласен с тем, что код Ника из комментария ниже предпочтительнее.

person Meru Bhanot    schedule 16.09.2015
comment
Это уменьшает до bysort test (id) : replace id = _n if missing(id). - person Nick Cox; 16.09.2015

В поучительных целях подход @Nick egen можно обобщить дальше:

clear

input id str1 test
1     A
2     A
3     A
.     B
.     B
.     C
.     C
.     C
.     C
.     D
.     E
.     E
.     E
end

levelsof test, local(test_levels)
local number_of_test_levels : word count `test_levels'

forvalues i = 1 / `number_of_test_levels' {
      count if missing(id) & test == "`=char(64 + `i')'"
      if `r(N)' != 0 {
          egen newid`i' = seq(), from(1) to(`r(N)')
          replace id = newid`i' if missing(id) & test == "`=char(64 + `i')'"
          drop newid`i'
      }
}

Что дает ожидаемый результат:

sort test id  
list

     +-----------+
     | id   test |
     |-----------|
  1. |  1      A |
  2. |  2      A |
  3. |  3      A |
  4. |  1      B |
  5. |  2      B |
     |-----------|
  6. |  1      C |
  7. |  2      C |
  8. |  3      C |
  9. |  4      C |
 10. |  1      D |
     |-----------|
 11. |  1      E |
 12. |  2      E |
 13. |  3      E |
     +-----------+
person Community    schedule 05.06.2018