按用户聚合数据框,在首次处理之前为每个用户保留行
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))),]
本网站其他地方也有类似的问题,但 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))),]