在R中按时间与事件发生拆分数据并构建含时变常数的proportional hazard model时遇到的问题
嗨,看起来你在处理时变协变量的生存分析问题时卡壳了,我来帮你捋清楚怎么解决~
首先我完全理解你的需求:要做一个比例风险模型,关注创伤事件后不同洗脱期(0/1/3/5年)内的疾病发生风险,而且只有疾病发生在创伤之后、且过了对应洗脱期,才算作创伤相关事件。现在用tmerge拆分数据后事件全变成0,大概率是事件定义或tmerge的使用逻辑出了问题,我们一步步来修正。
先理清核心逻辑与数据定义
你的原始数据里有几个关键时间点,得先把它们的关系理清楚:
- 研究起始:
Age_at_recruitment - 创伤发生:
Age_at_trauma(无创伤的个体,这个值要设成比随访结束时间更大的数,比如Age_at_censoring_death_end_of_study + 1,避免误判区间) - 疾病发生:
Age_at_illness(未发病则为NA) - 随访终止:
Age_at_censoring_death_end_of_study
核心规则:只有当疾病发生在「创伤+洗脱期」之后、且在随访期内,才算符合条件的结局事件,否则按删失处理。
第一步:预处理原始数据,定义合格事件
先把原始数据里的缺失值和事件状态理清楚,以1年洗脱期为例:
library(dplyr) library(survival) # 假设你的原始数据叫raw_df raw_df <- raw_df %>% mutate( # 给无创伤的个体设置一个远大于随访结束的时间,避免干扰区间拆分 Age_at_trauma = ifelse(is.na(Age_at_trauma), Age_at_censoring_death_end_of_study + 1, Age_at_trauma), # 计算创伤后1年的时间点 trauma_1y_post = Age_at_trauma + 1, # 定义合格的结局事件时间:符合条件用疾病发生时间,否则用随访终止时间 event_time = case_when( !is.na(Age_at_illness) & Age_at_illness >= trauma_1y_post & Age_at_illness <= Age_at_censoring_death_end_of_study ~ Age_at_illness, TRUE ~ Age_at_censoring_death_end_of_study ), # 定义结局状态:1=发生合格疾病,0=删失 event_status = case_when( !is.na(Age_at_illness) & Age_at_illness >= trauma_1y_post & Age_at_illness <= Age_at_censoring_death_end_of_study ~ 1, TRUE ~ 0 ) )
第二步:用tmerge正确拆分时变数据
tmerge的核心是把每个个体的随访拆分成不同区间,每个区间对应协变量的状态(这里是「是否过了创伤洗脱期」)。之前事件全为0,大概率是没正确关联事件状态,或者区间拆分逻辑错了:
# 构建基础时间框架:每个个体的起始和终止时间 base_df <- raw_df %>% select(id, start = Age_at_recruitment, end = Age_at_censoring_death_end_of_study) # 用tmerge拆分时间区间,生成时变协变量 tmerge_data <- tmerge( data1 = base_df, data2 = raw_df, id = id, # 标记创伤发生的时间点 trauma_event = event(Age_at_trauma), # 标记创伤后1年的时间点 trauma_1y_event = event(trauma_1y_post), # 关联结局事件:必须同时传时间和状态 outcome = event(event_time, event_status), # 生成时变协变量:过了创伤后1年则为1,之前为0 post_trauma_1y = tdc(trauma_1y_post) ) # 查看拆分结果,每个个体的随访会被拆分成2-3个区间,post_trauma_1y会在对应时间点切换0/1 head(tmerge_data)
这里的tdc()函数是tmerge专门用来生成时变协变量的工具,会在指定时间点后把协变量设为1,完美匹配洗脱期的需求。
第三步:拟合比例风险模型
现在用拆分好的时变数据拟合Cox模型就没问题了:
cox_model <- coxph(Surv(start, end, outcome) ~ post_trauma_1y, data = tmerge_data) summary(cox_model)
扩展到多个洗脱期
如果要同时比较0/1/3/5年的洗脱期,只需要在预处理阶段多计算几个时间点(比如trauma_0y_post = Age_at_trauma、trauma_3y_post = Age_at_trauma +3),然后在tmerge中生成对应的时变协变量(post_trauma_0y、post_trauma_3y等),之后可以把这些协变量同时放进模型,或者分别拟合模型对比结果。
为什么之前事件全为0?
你之前的问题大概率是这几个原因:
- 没正确定义合格事件:比如把所有疾病都当成了不符合洗脱期要求的事件,导致
event_status全为0 - 使用
tmerge时只传了事件时间,没传状态参数,导致结局被默认设为0 - 没处理无创伤个体的
Age_at_trauma,导致区间拆分逻辑混乱
可以先检查原始数据里有没有「疾病发生在创伤后+洗脱期之后」的案例,如果本身没有这样的事件,那事件全为0是正常的;如果有,那就是上面的步骤哪里没做好啦。
备注:内容来源于stack exchange,提问作者DW1310

