You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在R中按时间与事件发生拆分数据并构建含时变常数的proportional hazard model时遇到的问题

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.17 08:57:59