2015-08-04 8 views
4

Я прикладной исследователь, работающий в основном с общенациональными данными реестра, который делает переход от Stata к R. Пакет dplyr заставил большинство моих ежедневных задач управления данными работать плавно , Тем не менее, я в настоящее время борется с получением R для генерации новых переменных на основе вложенных циклов.R: Создание новых столбцов на основе вложенных циклов

Предположим, что у нас есть следующий набор данных по шести участникам, родившимся между 1990-1992 годами, с мерами по их средним показателям за период с 2001 по 2004 год.

* Stata 
clear all 
input id byear gpa2000 gpa2001 gpa2002 gpa2003 gpa2004 
1 1990 1.2 1.3 1.4 1.5 1.3 
2 1990 2.3 2.5 2.2 2.1 2.6 
3 1991 3.1 3.9 3.4 3.5 4.0 
4 1991 2.6 3.1 2.4 1.9 3.1 
5 1992 1.4 1.8 3.2 2.3 3.2 
6 1992 3.5 4.0 4.0 4.0 3.9 
end 
list 

    +--------------------------------------------------------------+ 
    | id byear gpa2000 gpa2001 gpa2002 gpa2003 gpa2004 | 
    |--------------------------------------------------------------| 
    1. | 1 1990  1.2  1.3  1.4  1.5  1.3 | 
    2. | 2 1990  2.3  2.5  2.2  2.1  2.6 | 
    3. | 3 1991  3.1  3.9  3.4  3.5   4 | 
    4. | 4 1991  2.6  3.1  2.4  1.9  3.1 | 
    5. | 5 1992  1.4  1.8  3.2  2.3  3.2 | 
    6. | 6 1992  3.5   4   4   4  3.9 | 
    +--------------------------------------------------------------+ 

Или то же самое в R:

df <- read.table(header=T, text="id byear gpa2000 gpa2001 gpa2002 gpa2003 gpa2004 
1 1990 1.2 1.3 1.4 1.5 1.3 
2 1990 2.3 2.5 2.2 2.1 2.6 
3 1991 3.1 3.9 3.4 3.5 4.0 
4 1991 2.6 3.1 2.4 1.9 3.1 
5 1992 1.4 1.8 3.2 2.3 3.2 
6 1992 3.5 4.0 4.0 4.0 3.9 
") 

Теперь я хотел бы, чтобы генерировать три новые переменные, которые измеряют средний балл каждого участника в возрасте 10-12 лет (gpa_age10 ... gpa_age12).

В Stata, я обычно делаю это путем вложенным для петель:

forval i = 10/12 { 
    gen gpa_age`i' = . 
    forval j = 1990/1992 { 
     replace gpa_age`i' = gpa`=`j'+`i'' if byear == `j' 
    } 
} 

Это приведет к следующему набору данных:

 +-----------------------------------------------------------------------------------------------+ 
    | id byear gpa2000 gpa2001 gpa2002 gpa2003 gpa2004 gpa_a~10 gpa_a~11 gpa_a~12 | 
    |-----------------------------------------------------------------------------------------------| 
    1. | 1 1990  1.2  1.3  1.4  1.5  1.3  1.2  1.3  1.4 | 
    2. | 2 1990  2.3  2.5  2.2  2.1  2.6  2.3  2.5  2.2 | 
    3. | 3 1991  3.1  3.9  3.4  3.5   4  3.9  3.4  3.5 | 
    4. | 4 1991  2.6  3.1  2.4  1.9  3.1  3.1  2.4  1.9 | 
    5. | 5 1992  1.4  1.8  3.2  2.3  3.2  3.2  2.3  3.2 | 
    6. | 6 1992  3.5   4   4   4  3.9   4   4  3.9 | 
    +-----------------------------------------------------------------------------------------------+ 

Я понимаю, что не может быть прямой перевод этого Stata-кода в R, но каков наилучший способ репликации этих результатов в R?

+1

Ваш набор данных Stata я (с 'input..end'), но поскольку вы хотите получить ответ с R, вы, вероятно, должны сделать то же самое для него. Вот руководство: http://stackoverflow.com/a/28481250/1191259 На мой взгляд, лучший способ сделать это - хранить ваши данные в длинном формате (id, byear, year, gpa), так как разбор пар переменных склонный к ошибкам подход к кодированию и совершенно ненужный в R. Если вы это сделаете, вы можете просто добавить возрастный столбец = year-byear. – Frank

ответ

3

Вы можете изменить форму data.frame на форму, где каждая строка представляет год для учащегося, используя пакет reshape2. Тогда вычисление возраста становится тривиальным. Вот полный код для выполнения этой задачи предполагается, что ваш data.frame из выше в переменном называется dat:

mdat <- melt(dat, id.vars=c('id', 'byear'), value.name='gpa') 
mdat %>% 
    mutate(year=as.numeric(gsub('gpa', '', variable))) %>% 
    select(id, byear, year, gpa) %>% 
    mutate(age=year-byear) 

Кроме того, вы можете получить data.frame запрошенного литья расплавленной data.frame:

dcast(mdat, id + byear ~ age, value.var='gpa') 
> id byear 8 9 10 11 12 13 14 
> 1 1990 NA NA 1.2 1.3 1.4 1.5 1.3 
> 2 1990 NA NA 2.3 2.5 2.2 2.1 2.6 
> 3 1991 NA 3.1 3.9 3.4 3.5 4.0 NA 
> 4 1991 NA 2.6 3.1 2.4 1.9 3.1 NA 
> 5 1992 1.4 1.8 3.2 2.3 3.2 NA NA 
> 6 1992 3.5 4.0 4.0 4.0 3.9 NA NA 
+1

Благодарим вас (и Фрэнк) за хорошее предложение. Мое резервирование против изменения набора данных связано с тем, что в большинстве моих проектов задействованы миллионы людей, которым следуют десятилетия. Я предполагаю, что перестройка наборов данных займет очень много времени, и было бы лучше рассмотреть альтернативные подходы. – user3102806

+0

Предполагая, что в вашем примере вы хотели бы рассчитать эти значения, возможно, для отсутствующих значений, плавких исключений, включая значения «NA», которые могут значительно перевесить стоимость перестройки для очень больших наборов данных. Кроме того, если ваши данные уже являются data.frame, перестройка должна быть относительно недорогой вычислительно. Вызов 'as.numeric (gsub' скорее всего будет вашим вычислительным узким местом в больших наборах данных. – cr1msonB1ade

2

Я знаю, что вопрос был отлично обрабатывается @ cr1msonB1ade, но, чтобы показать, что оП вложенным для версии петли в R, чтобы соответствовать отвечал Stata код:

for (i in 10:12) { 
    for (j in 1990:1992) { 
    gpadf[[paste0("gpa_age", i)]][gpadf$byear==j] <- 
       gpadf[[paste0("gpa", j+i)]][gpadf$byear==j] 
    } 
} 
Смежные вопросы