按用户聚合数据框,在首次处理之前为每个用户保留行

Aggregate dataframe by user, keeping rows for each user prior to first occurrence of treatment

本网站其他地方也有类似的问题,但 none 的答案涵盖了我需要做的一切。

我有一个数据框,我正试图将其更改为时变的。研究中的受试者可以从非治疗转变为治疗,但不能相反。受试者有多行治疗信息,我想找到第一个出现的治疗,这很简单。问题是不是每个人都有治疗的发生,因此每当我 运行 我的算法找到第一次出现时,这些人就会被删除。为了让我的问题更清楚:

ID    treatment    start.date    stop.date  
1        0         01/01/2002    01/02/2002  
1        0         01/02/2002    01/03/2002  
1        1         01/03/2002    01/04/2002  
1        0         01/04/2002    01/05/2002  
2        0         01/01/2002    01/02/2002  
2        0         01/02/2002    01/03/2002  
3        0         01/01/2002    01/02/2002  
3        1         01/02/2002    01/03/2002
3        0         01/03/2002    01/04/2002  

如您所见,2 从未接受过治疗。当我运行以下算法时,2被去掉了。

data$keep <- with(data, 
                     ave(treatment==1, ID ,FUN=function(x) if(1 %in% x) cumsum(x) else 2))
with(data, data[keep==0 | (treatment==1 & keep==1),]) 

有什么方法可以扩展此代码,使那些没有第一次出现的人保持不变 并且 保持每一行直到第一次出现的人出现?

总而言之,我希望我的数据如下所示:

ID    treatment    start.date    stop.date    
1        0         01/01/2002    01/02/2002   
1        0         01/02/2002    01/03/2002    
1        1         01/03/2002    01/04/2002   
2        0         01/01/2002    01/02/2002    
2        0         01/02/2002    01/03/2002  
3        0         01/01/2002    01/02/2002  
3        1         01/02/2002    01/03/2002

我们可以用不同的方式做到这一点。 data.table 的一个选项是在按 'ID' 列分组的 'treatment' 列上使用 if/else 条件。我们检查 if 处理中没有值等于 '1',然后 return Data.table 的子集 (.SD) 即 (if(!any(treatment==1)) .SD)或 else 即如果 '1' 值在 'treatment' return 治疗中等于 1 (which(treatment==1)[1L]) 的第一个值的位置索引,得到序列 ( seq) 并使用该数字索引对数据表进行子集化。 (.SD)

library(data.table)#v1.9.5+
setDT(data)[, if(!any(treatment==1)) .SD 
              else .SD[seq(which(treatment==1)[1L])], by = ID]
#     ID treatment start.date  stop.date
#1:  1         0 01/01/2002 01/02/2002
#2:  1         0 01/02/2002 01/03/2002
#3:  1         1 01/03/2002 01/04/2002
#4:  2         0 01/01/2002 01/02/2002
#5:  2         0 01/02/2002 01/03/2002
#6:  3         0 01/01/2002 01/02/2002
#7:  3         1 01/02/2002 01/03/2002

或者更紧凑的方法是依赖 'treatment' 中当前值和先前值之间的差异,并检查差异是否大于或等于 0。我们可以使用 diff-。在这种情况下,我得到了治疗和治疗滞后之间的差异(shift 默认情况下给出 'lag' 值。它是 data.table 开发版本中的新功能)

setDT(data)[, .SD[(treatment-shift(treatment, fill=0))>=0], by = ID]

或使用 dplyr 的类似方法。我们按 'ID' 分组,然后 filter 根据 'treatment'.

中当前值和先前值之间的差异对行进行分组
library(dplyr)
data %>% 
    group_by(ID) %>% 
    filter(c(0, diff(treatment)) >=0) 
#  ID treatment start.date  stop.date
#1  1         0 01/01/2002 01/02/2002
#2  1         0 01/02/2002 01/03/2002
#3  1         1 01/03/2002 01/04/2002
#4  2         0 01/01/2002 01/02/2002
#5  2         0 01/02/2002 01/03/2002
#6  3         0 01/01/2002 01/02/2002
#7  3         1 01/02/2002 01/03/2002

ave 来自 base R

data[with(data, as.logical(ave(treatment, ID, 
                  FUN=function(x) c(0, diff(x))>=0))),]