R语言生存分析:Cox回归

上次介绍了生存分析中的寿命表、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.karno3个变量做演示:

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
##                                
## 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)

R语言生存分析:Cox回归_第1张图片

 

可以看到sexage的回归系数随着时间变化基本没啥变化,稳定在0水平线上,和上面的检验结果一样。

还可以通过以下方式查看残差的变化:

ggcoxdiagnostics(fit.cox, type = "schoenfeld")
## `geom_smooth()` using formula 'y ~ x'

R语言生存分析:Cox回归_第2张图片

这张图反映的也是回归系数随时间的变化趋势,和上面的图意思一样,如果符合比例风险假设,那么结果应该是一条水平线,从图示来看,这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
         )

R语言生存分析:Cox回归_第3张图片

这个结果如果你觉得不好看,或者你还有其他的森林图想做到统一的样式,可以考虑之前的介绍的画森林图的方法进行个性化定制:

画一个好看的森林图

用更简单的方式画森林图

R语言画森林图系列3!

R语言画森林图系列4!

以上是Cox回归的主要内容,大家有问题可以加群或者评论区留言,下次继续介绍时依协变量Cox回归和时依系数Cox回归。

参考资料

  1. http://www.sthda.com/english/wiki/survival-analysis-basics

  2. https://www.emilyzabor.com/tutorials/survival_analysis_in_r_tutorial.html

  3. survival包帮助文档

  4. https://mp.weixin.qq.com/s/2rwxeaF_M0UnqPi2F9JNxA

你可能感兴趣的:(医学统计学,r语言,回归,开发语言)