上次介绍了生存分析中的寿命表、K-M曲线、logrank检验、最佳切点的寻找等,本次主要介绍Cox回归。
本推文不涉及理论,只有实操,想要了解生存分析的理论的请自行学习。
Cox回归
使用survival
包中的lung
数据集用于演示,这是一份关于肺癌患者的生存数据。time
是生存时间,以天为单位,status
是生存状态,1代表删失,2代表死亡。
rm(list = ls())
library(survival)
library(survminer)
str(lung)
## 'data.frame': 228 obs. of 10 variables:
## $ inst : num 3 3 3 5 1 12 7 11 1 7 ...
## $ time : num 306 455 1010 210 883 ...
## $ status : num 2 2 1 2 2 1 2 2 2 2 ...
## $ age : num 74 68 56 57 60 74 68 71 53 61 ...
## $ sex : num 1 1 1 1 1 1 2 2 1 1 ...
## $ ph.ecog : num 1 0 0 1 0 1 2 2 1 2 ...
## $ ph.karno : num 90 90 90 90 100 50 70 60 70 70 ...
## $ pat.karno: num 100 90 90 60 90 80 60 80 80 70 ...
## $ meal.cal : num 1175 1225 NA 1150 NA ...
## $ wt.loss : num NA 15 15 11 0 0 10 1 16 34 ...
可以使用cox回归探索危险因素。分类变量需要变为因子型,这样在进行回归时会自动进行哑变量设置。
lung$sex <- factor(lung$sex, labels = c("female","male"))
lung$ph.ecog <- factor(lung$ph.ecog, labels = c("asymptomatic", "symptomatic",'in bed <50%','in bed >50%'))
str(lung)
## 'data.frame': 228 obs. of 10 variables:
## $ inst : num 3 3 3 5 1 12 7 11 1 7 ...
## $ time : num 306 455 1010 210 883 ...
## $ status : num 2 2 1 2 2 1 2 2 2 2 ...
## $ age : num 74 68 56 57 60 74 68 71 53 61 ...
## $ sex : Factor w/ 2 levels "female","male": 1 1 1 1 1 1 2 2 1 1 ...
## $ ph.ecog : Factor w/ 4 levels "asymptomatic",..: 2 1 1 2 1 2 3 3 2 3 ...
## $ ph.karno : num 90 90 90 90 100 50 70 60 70 70 ...
## $ pat.karno: num 100 90 90 60 90 80 60 80 80 70 ...
## $ meal.cal : num 1175 1225 NA 1150 NA ...
## $ wt.loss : num NA 15 15 11 0 0 10 1 16 34 ...
拟合多因素Cox回归模型,这里我们只用sex/age/ph.karno
3个变量做演示:
fit.cox <- coxph(Surv(time, status) ~ sex + age + ph.karno, data = lung)
# 查看结果
summary(fit.cox)
## Call:
## coxph(formula = Surv(time, status) ~ sex + age + ph.karno, data = lung)
##
## n= 227, number of events= 164
## (1 observation deleted due to missingness)
##
## coef exp(coef) se(coef) z Pr(>|z|)
## sexmale -0.497170 0.608249 0.167713 -2.964 0.00303 **
## age 0.012375 1.012452 0.009405 1.316 0.18821
## ph.karno -0.013322 0.986767 0.005880 -2.266 0.02348 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## exp(coef) exp(-coef) lower .95 upper .95
## sexmale 0.6082 1.6441 0.4378 0.8450
## age 1.0125 0.9877 0.9940 1.0313
## ph.karno 0.9868 1.0134 0.9755 0.9982
##
## Concordance= 0.637 (se = 0.025 )
## Likelihood ratio test= 18.81 on 3 df, p=3e-04
## Wald test = 18.73 on 3 df, p=3e-04
## Score (logrank) test = 19.05 on 3 df, p=3e-04
结果解读和logistic回归的结果解读类似:超级详细的logistic细节解读
-
coef
是回归系数, -
exp(coef)
是HR值, -
se(coef)
是回归系数的标准误, -
z
是Wald检验的z值, -
Pr(>|z|)
是回归系数的P值, -
lower .95/upper .95
是HR值的95%可信区间。
Concordance= 0.645
是Cox回归的C-index,最后给出了Likelihood ratio test
似然比检验的统计量、自由度、P值;Wald test
的统计量、自由度、P值;Score (logrank) test
的统计量、自由度、P值。
想获得整洁的结果不需要自己提取,只要用神包broom
即可:
broom::tidy(fit.cox, exponentiate = T, conf.int = T)
## # A tibble: 3 × 7
## term estimate std.error statistic p.value conf.low conf.high
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 sexmale 0.608 0.168 -2.96 0.00303 0.438 0.845
## 2 age 1.01 0.00940 1.32 0.188 0.994 1.03
## 3 ph.karno 0.987 0.00588 -2.27 0.0235 0.975 0.998
-
estimate
:HR值(exp(coef)) -
std.error
:回归系数的标准误(se(coef)) -
statistic
:Wald检验的z值 -
p.value
:回归系数的P值 -
conf.low/conf.high
:HR的95%的可信区间
构建好Cox回归后,也可以用函数单独提取想要的结果,以下图片展示了可用于提取模型信息的函数,和logistic回归差不多:
进行Cox回归必须要符合等比例风险假设,关于什么是等比例风险假设,可以参考这篇文章:https://mp.weixin.qq.com/s/l1Sd_nB9XY11FZMuda7xBg
等比例风险的检验可以通过很多方法进行,比如K-M曲线,一般如果有交叉,那么可能不符合等比例风险假设,还可以通过各种残差分布来检验。
下面是Cox回归的等比例风险假设检验,检验方法是基于Schoenfeld残差:
ftest <- cox.zph(fit.cox)
ftest
## chisq df p
## sex 3.085 1 0.0790
## age 0.478 1 0.4892
## ph.karno 8.017 1 0.0046
## GLOBAL 10.359 3 0.0157
可以看到ph.karno
的P值是小于0.05的,其实是不满足等比例风险假设的,下一篇推文会说到不符合等比例风险假设时该怎么办。
这种方法是基于Schoenfeld残差,检验结果可以通过图示画出来:
library(survminer)
ggcoxzph(ftest)
可以看到sex
和age
的回归系数随着时间变化基本没啥变化,稳定在0水平线上,和上面的检验结果一样。
还可以通过以下方式查看残差的变化:
ggcoxdiagnostics(fit.cox, type = "schoenfeld")
## `geom_smooth()` using formula 'y ~ x'
这张图反映的也是回归系数随时间的变化趋势,和上面的图意思一样,如果符合比例风险假设,那么结果应该是一条水平线,从图示来看,这3个变量都是有点问题的,但是真实数据往往不可能是完美的,很少有完全符合要求的数据。
除了Schoenfeld残差外,ggcoxdiagnostics()
还支持其他类型,比如:"martingale", "deviance", "score","dfbetas" and "scaledsch"在,只需要在type
参数中提供合适的类型即可。
cox
回归也是回归分析的一种,可以计算出回归系数和95%的可信区间,因此结果可以通过森林图展示:
# 为了森林图好看点,多选几个变量
fit.cox <- coxph(Surv(time, status) ~ . , data = lung)
ggforest(fit.cox, data = lung,
main = "Hazard ratio",
cpositions = c(0.01, 0.15, 0.35), # 更改前三列的相对位置
fontsize = 0.7,
refLabel = "reference",
noDigits = 2
)
这个结果如果你觉得不好看,或者你还有其他的森林图想做到统一的样式,可以考虑之前的介绍的画森林图的方法进行个性化定制:
以上是Cox回归的主要内容,大家有问题可以加群或者评论区留言,下次继续介绍时依协变量Cox回归和时依系数Cox回归。
参考资料
-
http://www.sthda.com/english/wiki/survival-analysis-basics
-
https://www.emilyzabor.com/tutorials/survival_analysis_in_r_tutorial.html
-
survival包帮助文档
-
https://mp.weixin.qq.com/s/2rwxeaF_M0UnqPi2F9JNxA