我有一个不平衡的小组(对于大约80万人来说有700万次观察)。我想创建一个等于1
的新变量,如果该人曾对另一个问题做出回应yes
。具体来说,如果个体已经吸烟,我想创建一个等于1的假人。
所以,让我们说我的数据集看起来像这样(其中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 :(得分: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
答案 1 :(得分: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实现,但使用一元加解决方案将逻辑转换为整数。