如何合并tmerge生成的时变数据行以加速coxph模型拟合?
问题
我有一个通过tmerge生成的大型data.table,包含50余个时变变量,用于coxph模型拟合。数据集以patid标识患者,时间区间由tstart和tstop定义。多数模型仅需使用部分时变变量,但coxph模型的运行速度受数据集行数和时间点数量影响——即使行内除时间区间外的数据完全相同,仍会拖慢速度。
我需要一种高效的方法,合并那些除时间区间外指定协变量完全相同的连续行,以提升模型拟合速度。例如需将如下示例data.table转换为results:
library(data.table) example=data.table(patid = c(1,1,1,2,2,2), tstart=c(0,1,2,0,1,2), tstop=c(1,2,3,1,2,3), x=c(0,0,1,1,2,2), y=c(0,0,1,2,3,3)) results=data.table(patid = c(1,1,2,2), tstart=c(0,2,0,1), tstop=c(2,3,1,3), x=c(0,1,1,2), y=c(0,1,2,3))
我的数据集规模约为60万患者、2000万行、3650个时间点,合并行后应能显著提升模型速度。我目前的实现方法如下:
example=data.table(patid = c(1,1,1,2,2,2), tstart=c(0,1,2,0,1,2), tstop=c(1,2,3,1,2,3), x=c(0,0,1,1,2,2), y=c(0,0,1,2,3,3)) example = example[order(patid,tstart),] example[,matched:=x==shift(x,-1)&y==shift(y,-1),by="patid"] example[is.na(matched),matched:=FALSE,by="patid"] example[,tstop:=ifelse(matched,shift(tstop,-1),tstop)] example[,remove:=tstop==shift(tstop),by="patid"] example = example[is.na(remove) | remove==FALSE,] example$matched=NULL example$remove=NULL
但该方法代码复杂,且需逐个修改协变量判断逻辑,易出错;同时无法处理连续多个协变量值相同的时间区间。我希望能有更合理的实现方式,支持传入协变量列名向量作为输入(因列名会随循环变化)。
解决方案
针对需求,这里提供一种基于data.table分组和游程编码的高效实现,支持动态传入协变量列名,且能处理任意数量的连续相同协变量行:
library(data.table) # 定义合并函数 merge_consecutive_rows <- function(dt, covar_cols) { # 确保按患者和时间起点排序 setorder(dt, patid, tstart) # 按患者分组,标记连续相同协变量的组 dt[, group := rleidv(.SD), by = patid, .SDcols = covar_cols] # 按患者和组聚合,取每组的第一个tstart、最后一个tstop,协变量取组内任意值(因为组内相同) merged_dt <- dt[, .( tstart = first(tstart), tstop = last(tstop), .SD ), by = .(patid, group), .SDcols = covar_cols] # 去重协变量列(因为组内每行都一样,聚合后会重复) merged_dt <- unique(merged_dt, by = c("patid", "group")) # 移除临时分组列,按patid和tstart重新排序 merged_dt[, group := NULL] setorder(merged_dt, patid, tstart) return(merged_dt) } # 测试示例 example=data.table(patid = c(1,1,1,2,2,2), tstart=c(0,1,2,0,1,2), tstop=c(1,2,3,1,2,3), x=c(0,0,1,1,2,2), y=c(0,0,1,2,3,3)) # 传入协变量列名向量 results <- merge_consecutive_rows(example, covar_cols = c("x", "y")) print(results)
代码说明
- 排序保障:先用
setorder确保数据按patid和tstart排序,保证连续行是时间上的先后顺序。 - 游程编码分组:使用
rleidv函数,按指定协变量列对每个患者的行进行游程编码——连续相同协变量的行会被分配同一个group值,完美解决连续多组相同的问题。 - 聚合合并:按
patid和group分组,取每组的第一个tstart(区间起点)、最后一个tstop(区间终点),协变量直接保留组内值(因为组内所有行的协变量都相同)。 - 高效性:整个过程基于
data.table的底层优化,适合处理千万级别的大数据,避免了循环和逐行判断的低效操作。
适配场景
你可以在循环中动态传入不同的协变量列名向量,比如:
# 循环处理不同的协变量组合 covar_list <- list(c("x", "y"), c("x"), c("y", "z")) for (covars in covar_list) { merged_data <- merge_consecutive_rows(your_large_dt, covar_cols = covars) # 后续拟合coxph模型... }
内容的提问来源于stack exchange,提问作者D. Stevens
相关产品推荐
相关产品推荐

