首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >「Workshop」第三期:生存分析

「Workshop」第三期:生存分析

作者头像
王诗翔呀
发布2020-07-03 16:57:41
发布2020-07-03 16:57:41
2.8K00
代码可运行
举报
文章被收录于专栏:优雅R优雅R
运行总次数:0
代码可运行

第三期的 workshop 由吴涛介绍生存分析,点击原文可以跳转到B站观看视频。有些公式无法正常显示,请下载 markdown 文件后通过 typora 之类的软件查看。 GitHub 仓库:https://github.com/XSLiuLab/Workshop (持续更新)

资料

图书:生存分析应用[1]

R包:

  • 核心:survival
  • 常用建模与绘图:survminer[2]
  • (批量)Cox 建模与绘图:ezcox[3]

介绍

生存分析就是对直到某一事件发生所经历的时间(生存时间)进行建模

生存分析主要的应用:

  • 估计生存时间
  • 比较不同组的生存时间的差异
  • 生存时间和其他变量(协变量)的相关性

生存分析最重要的三个函数是:生存函数,风险函数

特征:删失,时间

主要的方法:

  • 参数法
  • 半参数法 cox回归
  • 非参数法 KM方法

两个函数

生存函数:个体存活到某个时间点t的概率,或者说到时间t为止,感兴趣的事件(T)没有发生的概率:

S(t)=pr(T>t)

风险函数:个体存活到某个时间点t,但是在接下来一个小的时间间隔后死亡的概率除以这个时间间隔的长度也就是瞬时死亡率:

$$h(t)=\lim\limits_{\delta\rightarrow0}\frac{pr(t<tt)}{\delta} $$

方法

参数法

先假设生存时间服从某些分布,再估计这些分布的参数

主要有指数分布和weibull分布

非参数法

Kaplan-Meier estimator

非参数法最常用的是KM估计(Kaplan-Meier estimator)

条件概率:

KM估计算的是条件概率:

对于这样的区间有这些情况:

I_j

中没有发生死亡或者删失,估计的条件概率就是1

I_j

中有删失,估计的条件概率也是1

I_j

中有死亡没有删失,估计的条件概率就是

1-d/r

d是死亡的个体数目,r是总的个体数目

所以KM法估计的生存函数就是:

算法:

  • 对失败时间进行排序
  • 对失败时间计算估计的生存概率
  • 移动到下一次失败时间,将之前的死亡和删失的数据剔除,再次计算生存概率,直到最后的失败时间
代码语言:javascript
代码运行次数:0
运行
复制
tt <- c(7,6,6,5,2,4)
cens <- c(0,1,0,0,1,1)
result.km <- survfit(Surv(tt, cens) ~ 1)
summary(result.km)
置信区间的估计

在估计方差前要了解一下delta method:如果一个随机变量有均值

\mu

和方差

\sigma^2

,那么对于足够大的样本g(x)就有近似的均值

g(\mu)

和方差

\sigma^2[g'(\mu)]^2

然后就可以使用这个方法估计方差:

再次使用delta method

但是基于这个方差算出来的置信区间可能大于1或者小于0,一个更好的方法是对log(-logS(t))估计置信区间:

survfit函数中加入conf.type参数就可以指定log-log方法

代码语言:javascript
代码运行次数:0
运行
复制
result.km <- survfit(Surv(tt, cens) ~ 1, conf.type="log-log")
plot(result.km)
log-rank比较两组生存时间的差异

原假设是:

H_0:S_1(t)=S_0(t)

S1和S0分别表示实验组和对照组的生存分布

备择假设是使用Lehman alternative:

H_A:S_1(t)=[S_o(t)]^\psi

也可以表示成:

h_1(t)=\psi h_0(t)

所以我们也可以将假设检验改为:

H_0:\psi =1 \\ H_A:\psi <1

接下来构建统计量:

对失败时间进行排序,对每个失败的时间都可以得到下面的二联表:

如果我们假设实验组和对照组没有差异,固定

n_{0i},n_{1i},d_i

那么

d_{0i}

服从超几何分布(可以理解为一个盒子里有

n_{0i}

个蓝色的球,

n_{1i}

个红色的球,不返回的抽取

d_i

个球,如果抽到红色和蓝色的球的概率是一样的,那么抽到的蓝色的球服从超几何分布)

期望和方差分别为:

e_{0i}=E(d_{0i})=\frac{n_{0i}d_i}{n_i} \\ v_{0i}=var(d_{0i})=\frac{n_{0i}n_{1i}d_i(n_i-d_i)}{n_i^2(n_i-1)}

然后把所有的失败时间的表的观察到的

d_{0i}

与其期望的差加起来得到一个统计量

U_0

,将所有的方差加起来得到

V_0

,之后,就可以得到一个服从正态分布或者卡方分布的统计量:

U_0=\sum_{i=1}^N(d_{0i}-e_{0i})=\sum d_{0i}-\sum e_{0i}\\ V_0=\sum v_{0i}\\ \\ \frac{U_0}{\sqrt{V_0}}\sim N(0,1)\\ \frac{U_0^2}{V_0}\sim \chi_1^2

然后就可以算p值了,当我们需要比较大于2组的的时候,实际上是在cox回归中通过score test来检验这个变量的回归系数

也可以将这种检验进行推广,给他加上一个权重,weighted log-rank test:

权重的确定可以把两组样本混合,然后计算Kaplan-Meier estimator得到:

这种检验也叫做Fleming-Harrington G(ρ) test,ρ=0的时候就是log-rank test,这种方法给早期的生存差异一个较大的权重

在R中可以直接用survdiff()来计算不同组的差异,这个函数的参数rho就是上面的权重中的ρ

代码语言:javascript
代码运行次数:0
运行
复制
##胰腺癌的二期临床数据
head(pancreatic)
  stage    onstudy progression      death
1     M 12/16/2005    2/2/2006 10/19/2006
2     M   1/6/2006   2/26/2006  4/19/2006
3    LA   2/3/2006    8/2/2006  1/19/2007
4     M  3/30/2006           .  5/11/2006
5    LA  4/27/2006   3/11/2007  5/29/2007
6     M   5/7/2006   6/25/2006 10/11/2006

library(asaur)
library(date)
library(survival)
head(pancreatic)
attach ( pancreatic )
Progression_d <- as.date(as.character(progression))
OnStudy_d <- as.date(as.character(onstudy))
Death_d <- as.date(as.character(death))
# compute progression free survival
progressionOnly <- Progression_d-OnStudy_d
overallSurvival <- Death_d-OnStudy_d
pfs <- pmin(progressionOnly , overallSurvival)
pfs[is.na(pfs)] <- overallSurvival[is.na(pfs)]

pfs_month <- pfs/30.5

plot(survfit(Surv(pfs_month) ~ stage), xlab="Time in months", ylab="Survival probability",
     col=c("blue", "red"), lwd=2)
legend("topright", legend=c("Locally advanced", "Metastatic"),
       col=c("blue","red") , lwd=2)

##log-rank
survdiff(Surv(pfs) ~ stage, rho=0)
survdiff(Surv(pfs) ~ stage, rho=1)

image-20200602105500615

image-20200602105737602

cox比例风险回归

首先定义一个风险比率:

\psi_i = e^{z_i\beta}

,

z_i

是协变量的值,β是系数,一个协变量一个系数:

h_i(t_j)=h_0(t_j)\psi_i ,\psi_i = e^{z_i\beta}

进行Log转化得到:

log(h_i(t_j))=log(h_0(t_j))+\beta_1z_1+\beta_2z_2+...\beta_px_p

这个就是cox风险比例回归模型,

对于时间t1,我们可以计算病人i失败的概率:

p1=\frac{h_i(t1)}{\sum_{k \in R_i}h_k(t_1)}=\frac{h_0(t_1)\psi_i}{\sum_{k\in R_1}h_0(t_1)\psi_k}=\frac{\psi_i}{\sum_{k \in R_i}\psi_k}

然后对于每一个时间(改变R,丢弃死亡的和缺失的数据)都可以算p,得到partial likelihood:

L(\psi)=p_1p_2...p_D

可以通过最大似然估计来计算系数β

然后就可以对系数进行检验,主要有三种检验Wald test, score test, likelihood ratio test

首先我们需要从log的似然函数中得到两个函数:

一个是分数函数 :是log似然函数的一阶导数:

S(\beta)=l'(\beta)

第二个是信息函数:是log似然函数的二阶导数:

I(\beta)=-S'(\beta)=-l''(\beta)

The Wald Test

可以构建一个Z统计量:

\hat{\beta}/s.e.(\hat{\beta})

,可以用

1/I(\hat{\beta})

来估计

\hat{\beta}

的方差,标准误为:

s.e.(\hat{\beta})=1/\sqrt{I(\hat{\beta})}

使用这个统计量来计算p值或者构建置信区间

The Score Test

score统计量为

Z_s=S(\beta=0)/\sqrt{I(\beta=0)}

如果

|Z_S|>z_{\alpha/2}

的时候拒绝原假设

\beta=0

这种方法不需要进行最大似然估计的

The Likelihood Ratio Test

这个检验来自统计学原理:

2[l(\beta=\hat{\beta})-l(\beta=0)]

近似服从自由度为1的卡方分布

在R里面可以使用coxph来进行cox回归分析

Survival analysis in R

用的包是survival包,示例数据是包内置数据集lung

代码语言:javascript
代码运行次数:0
运行
复制
?lung

主要用到的函数包括:

  • Surv()创建生存对象
  • survfit() 拟合生存曲线
  • coxph()拟合Cox比例风险回归模型
  • survdiff() 使用log-rank来检验多组生存时间的差异

Surv() 输入的是时间和状态(死亡或者删失),返回的结果是一个特殊的向量,对应的是每个时间发生的事件,用+表示删失:

代码语言:javascript
代码运行次数:0
运行
复制
s <- Surv(lung$time, lung$status)
head(s)
#[1]  306   455  1010+  210   883  1022+

接下来就可以用survfit()来拟合生存曲线:

代码语言:javascript
代码运行次数:0
运行
复制
sfit <- survfit(Surv(time, status)~1, data=lung)##不分组
sfit1 <- survfit(Surv(time, status)~sex, data=lung)##按性别分组

summary(sfit1)
summary(sfit1, times=seq(0, 1000, 100))##规定时间段

可以直接用plot来画图,也可以用survminer包中的ggsurvplot函数来画生存曲线图:

代码语言:javascript
代码运行次数:0
运行
复制
plot(sfit1)

library(survminer)
ggsurvplot(sfit1)

ggsurvplot(sfit1, conf.int=TRUE, pval=TRUE, risk.table=TRUE, 
           legend.labs=c("Male", "Female"), legend.title="Sex",  
           palette=c("dodgerblue2", "orchid2"), 
           title="Kaplan-Meier Curve for Lung Cancer Survival", 
           risk.table.height=.15)

图里面的p值是通过log-rank 检验计算的,也可以用survdiff来得到:

代码语言:javascript
代码运行次数:0
运行
复制
survdiff(Surv(time, status)~sex, data=lung)

进一步还可以用coxph()检测多个变量对生存的影响,这个函数输入的自变量是想要检查的变量,因变量是Surv()生成的对象:

代码语言:javascript
代码运行次数:0
运行
复制
fit <- coxph(Surv(time, status)~sex+age+ph.ecog+ph.karno+pat.karno+meal.cal+wt.loss, data=lung)
fit
summary(fit)

结果里面的第一列coef就是系数β,第二列exp(coef)就是

e^\beta

也就是风险比率(hazard ratio,HR),HR等于1没有效应,大于1表示风险增大,小于1风险减少,比如性别有男性和女性,以男性为基准,从男性到女性生存风险大概降低40%

可以通过逐步回归找到"有用"的变量:

代码语言:javascript
代码运行次数:0
运行
复制
fit <- coxph(Surv(time, status)~sex+age+ph.ecog+ph.karno+pat.karno+meal.cal+wt.loss, 
             data=na.omit(lung))
stepwise <- step(fit,scope = list(upper=~sex+age+ph.ecog+ph.karno+pat.karno+meal.cal+wt.loss,
                                  lower=~sex))
stepwise

AIC叫做赤池信息准则,是当使用似然函数作为目标函数计算模型参数时,衡量模型拟合优良性的一个标准:

k是模型参数,L是似然函数,从一组可供选择的模型中选择最佳模型时,通常选择AIC最小的模型

然后可以通过森林图来可视化cox回归的结果:

代码语言:javascript
代码运行次数:0
运行
复制
ggforest(fit3,data = lung)

参考资料

[1]

生存分析应用: survival-analysis-book.pdf

[2]

survminer: https://github.com/kassambara/survminer

[3]

ezcox: https://github.com/ShixiangWang/ezcox

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-06-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 优雅R 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 资料
  • 介绍
  • 两个函数
  • 方法
    • 参数法
    • 非参数法
      • Kaplan-Meier estimator
      • 置信区间的估计
      • log-rank比较两组生存时间的差异
  • cox比例风险回归
    • The Wald Test
    • The Score Test
    • The Likelihood Ratio Test
  • Survival analysis in R
    • 参考资料
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档