2016-06-21 57 views
0

我有一個不平衡面板(對於大約800k個人有700萬觀察值)。我想創建一個等於1的新變量,如果該人曾對另一個問題回覆yes。具體來說,我想創建一個假人,如果個人吸菸經常吸菸,就等於1。R:如何按組擴展條件

所以我們可以說我的數據集看起來是這樣的(其中ID是因人而異的,有的人被採訪了很多時間和其他人只有一次):

ID Smoke 
1  No 
1  No 
1  Yes 
1  No 
2  No 
2  No 
3  Yes 
3  No 

我想要生成可變Ever_Smoked,看起來是這樣的:

ID Smoke Ever_Smoked 
1  No   1 
1  No   1 
1  Yes   1 
1  No   1 
2  No   0 
2  No   0 
3  Yes   1 
3  No   1 

如何做到這一點任何想法? 在此先感謝!

+0

@Angustin Indaco您可以按照您嘗試的方式使用4個空格作爲縮進來格式化表格(這使得它們成爲源代碼)。 – geekoverdose

+0

謝謝,我試圖弄清楚如何做到這一點。很長一段時間,StackOverflow的狂熱讀者,第一次發佈一些東西。 –

回答

4

下面是使用ave()一個基礎R溶液:

df$Ever_Smoked <- ave(+(df$Smoke=='Yes'),df$ID,FUN=max); 
df; 
## ID Smoke Ever_Smoked 
## 1 1 No   1 
## 2 1 No   1 
## 3 1 Yes   1 
## 4 1 No   1 
## 5 2 No   0 
## 6 2 No   0 
## 7 3 Yes   1 
## 8 3 No   1 

數據

df <- data.frame(ID=c(1L,1L,1L,1L,2L,2L,3L,3L),Smoke=c('No','No','Yes','No','No','No','Yes', 
'No'),stringsAsFactors=F); 

巧合的是,today I did some benchmarking on different ways of converting a logical vector to an integer vector,發現一元加號是最快的。這就是爲什麼我選擇它作爲我在這裏的答案。

當然,對ave()的調用會產生顯着的性能影響,至少與data.table的索引實現相關。因此,爲了獲得最佳性能,我建議您使用rafa的data.table實現,但使用unary plus解決方案將邏輯轉換爲整數。

+0

是的,這非常快。而且我似乎可以很好地工作。謝謝! –

1

您可以沿着ID分割你的數據和相應的值分配給每個單獨的子集:

d <- data.frame(ID = c(rep(1,4), rep(2,2), rep(3,2)), Smoke=c('No', 'No', 'Yes', rep('No', 3), 'Yes', 'No')) 

library(plyr) 
d2 <- ldply(split(d, d$ID), function(d_tmp) { 
    d_tmp$Ever_Smoked <- ifelse(all(d_tmp$Smoke=='No'), 0, 1) 
    d_tmp 
})[,-1] 

...這應該是你打算要獲取的內容:

> print(d2) 

    ID Smoke Ever_Smoked 
1 1 No   1 
2 1 No   1 
3 1 Yes   1 
4 1 No   1 
5 2 No   0 
6 2 No   0 
7 3 Yes   1 
8 3 No   1 
5

鑑於大小的數據集,基於data.table的解決方案可能是最好的/最快的替代方案

library(data.table) 

setDT(df)[, Ever_Smoked := as.numeric(any(Smoke=="Yes")), by = ID] 
使用由@bgoldst提供的樣本數據

性能測試

df <- data.frame(ID=c(1L,1L,1L,1L,2L,2L,3L,3L),Smoke=c('No','No','Yes','No','No','No','Yes','No'),stringsAsFactors=F) 

# make it a 8 million row dataset 
df <- df[rep(seq_len(nrow(df)), 1000000), ] 

system.time(setDT(df)[, Ever_Smoked := as.numeric(any(Smoke=="Yes")), by = ID]) 

#> user system elapsed 
#> 0.27 0.01 0.32 
+0

我同意這一點 - 猜我應該建議更多的'data.table'解決方案; – geekoverdose

+2

雖然這並沒有給出正確的結果,因爲並非所有Ever_Smoked案件最終成爲一個組。你需要像setDT(df)[,Ever_Smoked:= as.numeric(any(Smoke ==「Yes」)),by = ID]'來代替。 – thelatemail

+0

好眼@thelatemail。 5 upvoters(包括我)沒有注意到它... – bgoldst