如何按组ID计算带协变量的时间区间并集与交集?
按组计算时间区间的交集与并集并保留协变量
针对按患者(id)分组计算干预时段(A)和药物治疗时段(B)的交集、并集,同时保留对应协变量的需求,以下是基于data.table的高效实现方案,可支持大规模数据集:
一、准备工作:统一数据结构(添加分组id)
先给示例数据补充分组id,模拟真实场景下的多患者结构:
library(data.table) # 补充id字段,模拟单患者场景(实际多患者只需扩展id值即可) A <- data.table( id = 1, start = as.Date(c("2022-10-16", "2023-06-16")), stop = as.Date(c("2023-03-12", "2023-10-12")), covar_A = c("P-int 1", "P-int 2") ) B <- data.table( id = 1, start = as.Date(c("2022-10-16", "2023-08-16")), stop = as.Date(c("2023-01-12", "2023-12-12")), covar_B = c("Drug 1", "Drug 2") )
二、计算区间交集(A ∩ B)
利用foverlaps()匹配重叠区间,直接计算交集时段并保留协变量:
# 设置data.table的键,用于区间匹配 setkey(A, id, start, stop) setkey(B, id, start, stop) # 执行区间重叠匹配 overlaps <- foverlaps(A, B, type = "any", nomatch = NULL) # 计算交集的起止时间:取两个区间的晚开始、早结束 overlaps[, `:=`( intersect_start = pmax(start, i.start), intersect_stop = pmin(stop, i.stop) )] # 筛选有效交集(开始时间 < 结束时间),整理结果 intersection <- overlaps[intersect_start < intersect_stop, .( id, 开始时间 = intersect_start, 结束时间 = intersect_stop, covar_A = covar_A, covar_B = covar_B )] # 查看结果 print(intersection)
分组处理时data.table会自动按id并行处理,效率极高,最终输出与预期交集结果一致。
三、计算区间并集(A ∪ B)
并集需要先拆分所有时间节点,生成连续区间后匹配对应协变量:
# 收集所有id下的时间节点(A和B的start、stop) time_points <- rbind( A[, .(id, time = start)], A[, .(id, time = stop)], B[, .(id, time = start)], B[, .(id, time = stop)] ) # 按id和时间排序,去重 time_points <- time_points[order(id, time)][!duplicated(.SD), .SD, .SDcols = c("id", "time")] # 生成连续区间:每个节点作为下一个区间的开始 time_points[, `:=`( 开始时间 = time, 结束时间 = shift(time, type = "lead") ), by = id] # 移除最后一行(无结束时间的节点) union_intervals <- time_points[!is.na(结束时间), .(id, 开始时间, 结束时间)] # 匹配A的协变量:找到区间所属的A时段 setkey(A, id, start, stop) setkey(union_intervals, id, 开始时间, 结束时间) union_intervals <- foverlaps(union_intervals, A, type = "within", nomatch = NA)[, .( id, 开始时间, 结束时间, covar_A = i.covar_A )] # 匹配B的协变量:找到区间所属的B时段 setkey(B, id, start, stop) setkey(union_intervals, id, 开始时间, 结束时间) union_intervals <- foverlaps(union_intervals, B, type = "within", nomatch = NA)[, .( id, 开始时间, 结束时间, covar_A, covar_B = i.covar_B )] # 按时间排序结果 union_intervals <- union_intervals[order(id, 开始时间)] # 查看结果 print(union_intervals)
这段代码会生成预期的并集输出,空白时段(无A/B覆盖)的协变量会自动填充为NA。
四、扩展到多患者场景
上述代码天然支持多患者:只需在A和B数据中包含不同的id值,data.table的分组操作(by = id)会自动处理每个患者的区间,无需额外修改。对于数千患者、数万个区间的数据集,data.table的内存操作和分组优化能保证高效运行。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

