R语言cph函数设offset加surv=TRUE报错及系数约束咨询
问题场景
- 在R环境开展预测5年事件风险的Cox模型外部验证与更新工作,无原始建模数据,仅掌握线性预测子计算公式、5年时间点的基线生存概率取值
- 已在自有数据集完成原模型校准度、区分度评估,确认模型需要更新,本次更新仅调整基线风险,因此将线性预测子
beta.sum作为偏移项(offset)纳入Cox模型,固定其系数为1 - 计划使用
rms包的cph函数替代survival包的coxph函数,以便通过自助法便捷完成内部验证,但将线性预测子作为offset纳入模型时触发报错
报错信息:
Error in exp(object$linear.predictors) : non-numeric argument to mathematical function
- 已知现象:不设置
surv=TRUE参数时模型可正常运行,但后续需要调用的calibrate、validate、predictSurvProb等功能无法正常使用 - 核心疑问:该报错是操作错误导致,还是
cph函数本身不支持在公式中设置offset项;如果确实不支持,是否有其他方法可将线性预测子的系数约束为1
复现代码
业务场景实现代码
load(file="k.Rdata") ### 预测风险计算 ### # 计算线性预测子(LP) k$beta.sum <- -0.2201 * ((k$age/10)-7.036) + 0.2467 * (k$male - 0.5642) - 0.5567 * ((k$epi/5)-7.222) + 0.4510 * (log(k$acr_mgmmol/0.113)-5.137) k$pred <- 1 - 0.9365^exp(k$beta.sum) # 重校准模型 # 用coxph实现的可运行版本 cox.new <- coxph(Surv(time, rrt) ~ offset(beta.sum), data = k, x=TRUE, y=TRUE) # 计算更新后的5年基线生存概率 library(pec) predictSurvProb(cox.new, newdata=data.frame(beta.sum=0), times = 5) # 基线值 = 0.9570 # 用cph实现的报错版本 cph.new <- cph(Surv(time, rrt) ~ offset(beta.sum), data=k, x=TRUE, y=TRUE, surv=TRUE)
最小可复现代码
library(purr) library(rms) n <- 1000 set.seed(1234) status <- as.numeric(rbernoulli(n, p=0.1)) time <- -5* log(runif(n)) lp <- rnorm(1000, mean=-2.7, sd=1) mydata <- data.frame(status, time, lp) test <- cph(Surv(time, status) ~ offset(lp), data=mydata, surv=TRUE)
问题原因
该报错并非操作错误,是cph函数的兼容性问题:当模型仅在公式内设置offset()、无任何协变量且开启surv=TRUE时,内部计算基线生存函数的逻辑无法正确读取偏移项值,会将线性预测子赋值为NULL,后续调用exp()做指数运算时就会触发非数值参数报错。
解决方案
以下两种方案均可实现“固定线性预测子系数为1、仅更新基线风险”的需求,且能正常调用cph配套的校准、验证、预测功能:
方案1:将偏移项移至公式外传入,避开公式内offset的兼容bug
不要在模型公式内写offset(),将线性预测子传入cph函数的独立offset参数即可,写法和coxph结果完全等效:
cph.new <- cph(Surv(time, rrt) ~ 1, # 公式仅保留截距(基线风险) offset = beta.sum, # 偏移项写在公式外的参数位置 data = k, x=TRUE, y=TRUE, surv=TRUE)
该写法拟合的模型5年基线生存概率和coxph版本结果一致,calibrate、validate、predictSurvProb均可正常调用。
方案2:手动约束线性预测子系数为1,完全绕开offset逻辑
如果上述写法仍有兼容问题,可以直接将线性预测子作为协变量纳入模型,通过参数约束将其回归系数固定为1,效果和使用offset完全等价:
# 先设置rms包要求的数据分布对象 dd <- datadist(k) options(datadist = "dd") # 定义系数约束:将beta.sum的系数固定为1 constr <- rbind(c(1,1)) cph.new <- cph(Surv(time, rrt) ~ beta.sum, data = k, x=TRUE, y=TRUE, surv=TRUE, parms = constr)
该方法完全避开offset相关的计算逻辑,所有rms配套功能均不受影响。
内容的提问来源于stack exchange,提问作者FMaher
相关产品推荐
相关产品推荐

