r library car_用R来做Kaplan-Meier 生存分析

首先是在自己服务器里安装R,这一步可以直接借用conda来完成,推荐用jupyter notebook来运行R简单好用~,具体设置的可以参考“jupyter notebook中添加 R内核"

测试数据和代码见:https://github.com/leiwaaping/survival-analysis-with-TCGA-dataset

以下是文字介绍和部分内容我自己的理解说明:

做这个分析的时候,生存分析相关的一个包RTCGA刚好升级到只兼容3.6版本以上的R,然而我的R还是以前安装的旧版,所以一直报错,中间折腾了好久也只是报告说某个包无法安装完成,特定安装了被报有问题的包也依然无法解决问题,于是回到bioconda的文件里看每个包的限制条件,才发现是版本问题,所以吸取教训,看报错和找到真正的问题点很重要。

简单来说生存分析的就是已知一群人的生存情况(有可能是只活了一段时间,有可能是一直活着的),现在得知了这群人的另外一些数据,依着这些数据对这群人进行分组,然后每组的人分别进行生存率作图(横坐标是生存的时间长度,纵坐标是这段时间的这一组人的生存率,如一开始有100人,30天后10人死亡,则此时生存率从100%下降到90%)如果中途有人的数据丢失,病人不再回到医院复诊无法确认是否仍然生存,则记一个“+”在图上标出。一般来说最好有200个以上的样本才比较好做生存分析(考虑数据缺补情况)。生存分析的P值是指当前结果是随机出现的概率,P值越小,结果越可信

ad5fe37f4a06174ce4a796d486add145.png
三种疾病人群的生存分析,按疾病种类来分组,再各自画生存曲线,得到“不同疾病的生存情况不同”的结果。曲线下降得越快,证明这组的死亡率越高。

生存分析概念

在病人的临床信息中心,会有“临床试验终点"(end point),根据实验设计不一样,又可以分为不同的研究指标(OS,PFS,DFS,TTP),根据研究目的不同可以选择不同的终点。

Overall survival(OS,总生存): 0=存活;1=任何原因的死亡;t=随机化开始至死亡的时间。 这个是肿瘤临床试验中的最佳指标,因为好记录。临床试验中常用到5年OS生存率,肿瘤患者经过各种中和治疗后,生存五年以上的患者比例。也有用10年生存率来表示疗效的。

Progression-free survival(PFS,无进展生存期):0=存活;1=肿瘤发生任何方面的进展(复发转移)或者任何原因的死亡;t=随机化开始至肿瘤进展/死亡的时间。常用的有3年PFS生存分析,t>3的患者,统一t=3,p=0。PFS相比OS包含了恶化这个概念,可用于评估一些治疗的临床效益。

Time to progress(TTP,疾病进展时间):0=存活;1=肿瘤发生任何方面的进展(复发转移)。质保函了肿瘤恶化,不包含死亡。t=随机化开始至肿瘤进展的时间

disease-free survival(DFS,无病生存期):0=存活;1=疾病复发或者任何原因的死亡;t=随机化开始至疾病复发/死亡的时间。

Censoring(删失):这经常会在临床资料中看到,生存分析中也有其对应的参数,一般指不是由死亡引起的的数据丢失,可能是失访,可能是非正常原因退出,可能是时间终止而事件未发等等,一般在展示时以‘+’号显示,可分为:

  • left censored(左删失):只知道实际生存时间小于观察到的生存时间
  • right censored(右删失):只知道实际生存时间大于观察到的生存时间
  • interval censored(区间删失):只知道实际生存时间在某个时间区间范围内

基础版生存分析画图

已知样本的生存时间,当前状态(overall survival time/ PFS(按肿瘤进展来划分,考虑了死亡/复发等情况)),和分组数据,有一些可能要根据某数值大小来分组,可选用下文更详细的分组代码。有一些数据直接就分好组了,可以直接整合并画图

library(survival)
library(ggplot2)
library(ggpubr)
library(magrittr)
#install.packages("survminer")
library(survminer)
library(dplyr)


groupedclin<-as.data.frame(info)
colnames(groupedclin)
colnames(groupedclin)=c("overall_survival_Event","Overall_Survival_Time","PFS","PFS_T","group")
head(groupedclin)

# How many samples of each type?
table(groupedclin$group)

# Tabulate by outcome
xtabs(~group+overall_survival_Event, data=groupedclin) %>% addmargins()

coxph(Surv(Overall_Survival_Time, overall_survival_Event)~group, data=groupedclin)
sfit <- survfit(Surv(Overall_Survival_Time, overall_survival_Event)~group, data=groupedclin)
ggsurvplot(sfit, conf.int=TRUE, pval=TRUE)

89e2f0e1fa5a42155952fd9db9059593.png
head(groupedclin)

cadb2a2eb7febf077b8fd438d3bb8614.png

cox比例风险分析

- The Cox proportional-hazards model (Cox, 1972) Cox比例风险模型是常用与医学研究中的回归模型,通常用于研究预测变量与生存时间的关系
- Kaplan-Meier curves 与 logrank test tests属于单因素分析的例子,他们研究的是单一变量与生存的关系,并且Kaplan-Meier 与log-rank检验只适用于分类变量,却并不适用于数值型变量,比如我们常见的基因表达
- Cox比例风险回归分析的优势在于可以分析分类变量与数值变量,并且将生存分析的范围由单因素拓展到多因素的分析.

cox比例风险分析,同时评估几个因素对生存的影响。(如预后治疗方法、年龄、性别同时纳入考虑生存率)

2259c9d5154002eaec86510f90fa8036.png
head(info) 输入数据
#PFS=status PFS_T = time
#单因素Cox回归分析
res.cox <- coxph(Surv(PFS_T, PFS) ~ treatmentArm, data = info)
summary(res.cox)

451f77f99e23af4f32bf1947a8bf8253.png
看p值,并没有小于0.05,所以其实这个因素对生存结果影响不大
#批量进行单因素Cox生存分析
covariates <- c("age",  "gender", "TNstage", "SMART","group")
univ_formulas <- sapply(covariates,function(x) as.formula(paste('Surv(PFS_T, PFS)~', x)))
#univ_formulas
univ_models <- lapply( univ_formulas, function(x){coxph(x, data = info)})
#univ_results
#要整理输出,注意要一个因素一行才行,像treatmentArm这样子chr类型的,会被当成不同种类而有不同的p-value(见下文多因素的输出)
#chr类型会被堪称不同种类,所以要变成numeric(看age)
univ_results <- lapply(univ_models,
                       function(x){ 
                          x <- summary(x)
                          p.value<-signif(x$wald["pvalue"], digits=2)
                          wald.test<-signif(x$wald["test"], digits=2)
                          beta<-signif(x$coef[1], digits=2);#coeficient beta
                          HR <-signif(x$coef[2], digits=2);#exp(beta)
                          HR.confint.lower <- signif(x$conf.int[,"lower .95"],2)
                          HR.confint.upper <- signif(x$conf.int[,"upper .95"],2)
                          HR <- paste0(HR, " (", 
                                       HR.confint.lower, "-", HR.confint.upper, ")")
                          res<-c(beta, HR, wald.test, p.value)
                          names(res)<-c("beta", "HR (95% CI for HR)","wald.test", "p.value")
                          return(res)
                          #return(exp(cbind(coef(x),confint(x))))
                         })
res <- t(as.data.frame(univ_results, check.names = FALSE))
as.data.frame(res)

39005026a394a29621f48930713e8eb6.png
输出

同时考虑多个因素,看这些因素如何共同影响生存时间

#多因素Cox生存分析
res.cox <- coxph(Surv(PFS_T, PFS) ~ x + treatment + age +gender + STAGE + batch, data = dat)  
res.cox

a6d334167edf81c0e23f1ad3e48125da.png
因素Cox生存分析 输出

如果需要每个基因逐一放入cox模型中,检查基因的风险度,同时增加协变量来矫正

library(survival)
#(100位数以内)取消科学计数法
options(scipen = 100)

coxR<-lapply(11:(dim(dat)[2]),function(x){
#coxR<-lapply(11:19,function(x){
    n=dat[,x]
    res.cox <- coxph(Surv(PFS_T, PFS) ~ n + treatment + age +gender + STAGE + batch, data = dat)  # complex Coxph, ori expr
    s <- summary(res.cox)
    gene<-colnames(dat)[x]

    #也可以单独提取信息,但千万要注意选定好p-value 和HR,不同特征的位置不一样
    p.value<-signif(signif(s$coefficients)[1,5], digits=3)
    HR <-exp(signif(s$coefficients[1], digits=3))
    res<-c(gene,HR,p.value)
    return(res)
    })
res <- t(as.data.frame(coxR, check.names = FALSE))
row.names(res)=res[,1]
res=as.data.frame(res[,-1])
res[] <- lapply(res, function(x) {
    if(is.factor(x)) as.numeric(as.character(x)) else x
}) 
colnames(res)=c("HR","pvalue")

res_p0=res[res[, "pvalue"]<0.05,]
res_p0=res_p0[order(res_p0[,"HR"],decreasing=TRUE),]
head(res_p0)

65b35f081fb0382ceecf943d31e9eeb8.png
res_p0

468528d1a2bb56104794b4dca9161cbc.png
dat

Cox回归分析代码参考:

R语言生存分析03-Cox比例风险模型

Cox分析summary结果含义:

Hazard ratios. The exponentiated coefficients (exp(coef) ), 瞬时“掉血”速度,一般用来衡量药物的治疗效果。约远离1表示干预效果越大(有利或有害两个方向)

Cox Proportional-Hazards Model

下面的其实可以不用看了,是专门针对TCGA的样本,过滤并人工分组,查看生存率的一个例子。

拓展:提取符合要求的TCGA的样本生存数据

TCGA数据库和样本命名规则可以参考:https://zhuanlan.zhihu.com/p/46520322

1.TCGA数据有可能出现一个人多次检测多个样本的情况,由于生存分析一人对应一个数据,所以一般酌情删除后面测试的数据,只保留该名患者第一次的数据。如果是用自己的数据来算,有可能出现这种情况,可以用“去重”操作

2.TCGA的样本名字中间一般用“-”间隔,但不排除自己实验得到的数据样本名用了别的间隔符,要注意修正过来避免后期没有一个样本匹配上的。

expr<-read.table("doc/JCI121476.sdt12.txt", header = TRUE, stringsAsFactors=F)
#sort to remove duplicate
expr<-expr[order(expr$Sample_ID,decreasing = T),]
expr$Sample_ID<-substr(expr$Sample_ID,1,12)
dim(expr)
expr[1:2,]
expr<-expr[!duplicated(expr$Sample_ID, fromLast=TRUE), ]
dim(expr)
expr$Sample_ID<-gsub("_", "-",expr$Sample_ID)
expr[1:2,]

c073f2bb486702ce0d5100f187adb98e.png
去重复后从8678样本变为了8616样本,间隔符也替换了

3. 删除低质量样本

9d3e325491d60c243de5f759e303e624.png

一般看participant来确认是哪一个人,很多数据集会只显示前四个数来区别样本。需要注意的是,最后一个数“01C”,01~09表示肿瘤,10~19表示正常对照,一般01和11最常见。还有区分转移性和复发性的数据,详见https://gdc.cancer.gov/resources-tcga-users/tcga-code-tables/sample-type-codes

后面的vial指在一系列患者组织中的顺序,绝大多数样本该位置编码都是A; 很少数的是B,表示福尔马林固定石蜡包埋组织,一般我只保留A的数据,因为对B、C等数据没有了解,无法保证数据质量。一般B和C的不多,我都手动检查和删除了。

4.样本合并

并不是所有TCGA的样本都集合了分组数据和生存数据的,用merge来依据样本名来进行数据合并。(如图,有457个样本的该疾病的生存数据,但是只有277个样本既有herv表达量又有生存数据。)

library(RTCGA)
rownames(infoTCGA())
library(RTCGA.clinical)
library(RTCGA.mRNA)

#expr[,which(colnames(expr)=="herv_2965")]
singleherv<-expr[,c(1,which(colnames(expr)=="herv_2965"))]
#singleherv[1:4,]
clin <- survivalTCGA(COAD.clinical,extract.cols="admin.disease_code")
#Show the first few lines

dim(clin)
clin[1:4,]
colnames(clin)[2] <- "Sample_ID"
clinsample<-merge(clin,singleherv,by="Sample_ID",all=FALSE)
colnames(clinsample)[5] <- "expr"
dim(clinsample)
clinsample[1:4,]

eb08f29c3af312398c9fd4a5a379b768.png

进行生存分析

library(survival)
library(ggplot2)
library(ggpubr)
library(magrittr)
library(survminer)

#分组
library(dplyr)
a1<-as.numeric(mean(clinsample$expr))
g1<-clinsample[which(clinsample$expr<a1),]
g1$group=1
#g1[1:4,]
g3<-clinsample[which(clinsample$expr>=a1),]
g3$group=3
#g3[1:4,]
groupedclin<-as.data.frame(rbind(g1,g3))
# How many samples of each type?
table(groupedclin$group)
# Tabulate by outcome
xtabs(~group+patient.vital_status, data=groupedclin) %>% addmargins()

063f32463a34fb8b3bca5634a424fd7c.png
按照平均值分成两组,一组样本224个,另一组样本53个
  1. 基本来说就是依照数据,再原来的临床数据后面加一个分组,分组可以用数字表示,也可以用文字表述,status 0 /1 表示生存与否。如下面:

15b6a587cd5c00196b5d6024909feae7.png

2. 关于分组,可以采取文字(如上图),可以采取众数,可以采取平均值(如果有很多0的情况),也可以采取上/下四分位数的情况,看自身数据决定。(生存分析图只是一个辅助说明的作用,有些参数调整可能得到的图结果就不一样了,具体需要一个怎么样的图,可以再合适的范围内酌情调整优化)

#看一下数据分布
#see score distributation
hist(individual.socre$Score,breaks=100)

#取上/下四分位数或众数
quantile(individual.socre$Score)[2]
quantile(individual.socre$Score)[4]
as.numeric(strsplit(as.character(quantile(individual.socre$Score)[2]), ":")[[1]])
as.numeric(strsplit(as.character(quantile(individual.socre$Score)[4]), ":")[[1]])
median(individual.socre$Score)

25%: 6479.38306575775%: 8043.83190523448
6479.383065757
8043.83190523448
7134.55590193063

画图

coxph(Surv(times, patient.vital_status)~group, data=groupedclin)
sfit <- survfit(Surv(times, patient.vital_status)~group, data=groupedclin)
summary(sfit, times=seq(0,365*5,365))
ggsurvplot(sfit, conf.int=TRUE, pval=TRUE)

8cea047e4f39709143e1d1f08362367a.png
与红线相比,绿线组患者的危险仅增加至1.08倍(exp(coef))

4854ad5fb99533b4f1ed6df366ae4268.png
背景颜色部分是置信度,两个置信度覆盖部分越高P值越大,如图其实能得到结论,这个herv表达量与生存率没有什么关系了
  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值