R:如何按组扩展条件

时间:2016-06-21 22:26:17

标签: r dataframe

我有一个不平衡的小组(对于大约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

关于如何做到这一点的任何想法? 提前谢谢!

2 个答案:

答案 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实现,但使用一元加解决方案将逻辑转换为整数。