生存分析:将事件的结果(终点事件)和出现这一结果所经历的时间结合起来的一种统计分析方法。
生存分析的目的:
1.生存率比较:估计处理组和对照组n年的生存率和中位生存期。
2.生存曲线比较:比较处理组和对照组的生存率是否有差别。
3.影响因素分析:分析变量与生存结局/事件的关系。
4.生存预测:根据变量预测患者n年的生存率。
从生存分析的方法上看,一般可以分为三类:
1.参数法:知道生存时间的分布模型,然后根据数据来估计模型参数,最后以分布模型来计算生存率。如Weibull回归、lognormal回归等。一般不用,因为目前认为我们不知道生存时间符合什么模型。
2.非参数法:不需要生存时间分布,根据样本统计量来估计生存率。常见方法Kaplan-Meier分析(乘积极限法)、寿命法(Life Tables)。而对于Kaplan-Meier法来说,其中的p值我们常用log-rank检验(对数秩检验)和Wilcoxon检验去求。
3.半参数法:也不需要生存时间的分布,但最终是通过模型来评估影响生存率的因素。最为常见的是Cox比例风险回归模型。
1.单因素生存分析:描述生存过程。 常用的单因素分析方法有乘积极限法(Kaplan-Meier分析)和寿命表法(Life Tables)。
2.多因素生存分析:分析生存过程的影响因素。常用的多因素生存分析方法有Cox比例风险回归模型。
在简单生存分析中,由于仅考虑单个影响因素(且为分类型或顺序型变量),故采取的是直接绘制生存曲线并作Log-Rank检验来判断影响因素和生存概率的方法。
而在Cox回归分析中,需要同时考虑多个影响因素(可为分类/顺序型变量,也可为数值型变量),故而绘制生存曲线的方式显然不合适,此时就需通过建模的方法来进一步分析。
单个变量的Cox回归和K-M法结果不一致时,此时我们还是应该选择Cox的结果,因为参数检验效力高于非参数检验。
多个变量的Cox回归中单个变量的显著性与K-M法不一致,此时我们应该选择cox的结果,因为K-M发只考虑单个变量,而Cox考虑了多个变量。
描述性统计分析:Kaplan-Meier分析:非参数估计,不要求总体的分布形式,直观地表现出两组或多组的生存率或死亡率,适合在文章中展示。
统计推断:组间比较:log-rank检验,两组之间生存率的差异是否显著。
Kaplan-Meier analysis 单因素生存分析绘图 KM-Plot
1 2 3 4 5 6 | rm (list = ls ()) library (survival) library (survminer) library (pbapply) setwd ( "D:/BioInformationAnalyze/TCGAdata/CRC" ) load ( "TCGA-COAD_04.lncRNA_SurvData.Rdata" ) # 生存分析输入数据,包含tpm形式的表达矩阵和临床信息 |
需要的文件有基因表达文件(exprSet)和生存数据文件(meta),文件格式如下:
年龄
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | sfit <- survfit ( Surv (time, event) ~ age_group, data = meta) # Surv()函数创建生存数据对象(主要输入生存时间和状态逻辑值) # survfit()函数对生存数据对象拟合生存函数,创建KM(Kaplan-Meier)生存曲线 # time表示总生存期 # event表示终点事件,1死亡,0存活。 # ~age_group表示以年龄分组绘图,注意此方法仅适用二分类变量进行分组。如果不想分组,只看总体,~1即可 # 如果想看整体的sfit结果,可以summary(sfit) 或 summary(sfit)$table, # 想看每个时间点的更好的方式则是:surv_summary(sfit): # time:曲线上的时间点。 # n.risk:时间t时面临风险的受试者数量. # n.event:在时间t发生的事件数。 # n.censor:在时间t时退出风险集且没有事件的受审查对象的数量。 # surv:生存概率的估计。 # std.err:生存的标准误差。 # upper:置信区间的上限。 # lower:置信区间的下限。 # strata:表示生存曲线的分层。如果分层不为 NULL,则结果中存在多条曲线。分层(因子)的水平是曲线的标签。 # 根据上述sfit结果,我们可以将KM生存数据进行可视化,主要使用Survminer包的ggsurvplot()函数: ggsurvplot (sfit, conf.int = FALSE , pval = TRUE ) # 通过设置参数,可在生存曲线基础上,再绘制两张辅助图: ggsurvplot (sfit, palette = c ( "#E7B800" , "#2E9FDF" ), pval = TRUE , conf.int = TRUE , # 显示p值和置信区间 xlab = "Time in months" , # x轴标签 linetype = "strata" , # 线条类型 # fun = "event", # 绘制cumulative events图,即事件发生累计概率图 ggtheme = theme_light (), # 更改 ggplot2 主题 surv.median.line = "hv" , # 指定中位生存期 risk.table = TRUE , # Number at risk图,表示在该生存时间长度内,还存活的case;较直接得反映出两组的一个差异情况。 # risk.table.col = "strata", # 按分组改变risk table的颜色 ncensor.plot = TRUE ) # Number of censoring图,即该时间段内的删失值。 |


性别、年龄
1 2 3 4 5 6 | sfit1 <- survfit ( Surv (time, event) ~ gender, data = meta) sfit2 <- survfit ( Surv (time, event) ~ age_group, data = meta) splots <- list () splots[[1]] <- ggsurvplot (sfit1, pval = TRUE , data = meta, risk.table = TRUE ) splots[[2]] <- ggsurvplot (sfit2, pval = TRUE , data = meta, risk.table = TRUE ) arrange_ggsurvplots (splots, print = TRUE , ncol = 2, nrow = 1, risk.table.height = 0.4) # 内置拼图函数 |

单个基因
设定某一基因的表达基准,将临床样本分为高表达high与低表达low两组,再进行生存分析。这里用表达矩阵的tpm值进行计算。
1 2 3 4 | g <- rownames (exprSet)[2] # 挑选基因,可修改成自己感兴趣的基因 meta$gene <- ifelse ( as.integer (exprSet[g,]) > median ( as.integer (exprSet[g,])), "high" , "low" ) sfit1 <- survfit ( Surv (time, event) ~ gene, data = meta) ggsurvplot (sfit1, pval = TRUE , data = meta, risk.table = TRUE ) |

多个基因
1 2 3 4 5 6 7 8 | gs <- rownames (exprSet)[1:4] # 挑选基因,可修改成自己感兴趣的基因 splots <- pblapply (gs, function (g){ meta$gene <- ifelse ( as.integer (exprSet[g,]) > median ( as.integer (exprSet[g,])), "high" , "low" ) sfit1 <- survfit ( Surv (time, event) ~ gene, data = meta) ggsurvplot (sfit1, pval = TRUE , data = meta, risk.table = TRUE ) }) arrange_ggsurvplots (splots, print = TRUE , ncol = 2, nrow = 2, risk.table.height = 0.4) # 内置拼图函数 |
log-rank批量生存分析
Log-Rank test:对不同组的生存率进行假设检验,是无参数检验,近似于卡方检验,零假设是组间没有差异。
由于log-rank检验需要对自变量进行分组,无法使用连续型变量,而有时候在不知道连续性变量的最佳截断值或者自变量很多的时候,只能按中位数进行分组,所以结果并没有Cox回归用连续型变量得出的结果好。所以一般先用Cox或Lasso将变量降维后,再找最佳截断值来画生存曲线。
Log-Rank检验属单因素分析方法,应用条件是除比较因素外,影响生存率的其他因素组件均衡可比,否则应矫正各因素的影响,可采用Cox比例风险回归模型。
用apply()函数批量计算所有表达矩阵中基因的生存分析p值,从而挑选出“显著基因”。这里用表达矩阵的tpm值进行计算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | mySurv <- with (meta, Surv (time, event == "1" )) # 创建生存对象,event == 1表示“1为结局时间发生“ log_rank_p <- pbapply (exprSet, 1, function (gene){ # gene <- exprSet[1,] meta$group <- ifelse (gene > median (gene), "high" , "low" ) data.survdiff <- survdiff (mySurv ~ group, data = meta) # survdiff()用于检验两条或多条生存曲线之间是否存在差异, # 或者针对已知替代项检验单条曲线,也适用于分组资料以及多组间生存曲线的比较; p.val <- 1 - pchisq (data.survdiff$chisq, length (data.survdiff$n) - 1) # 计算log-rank检验的p值 return (p.val) }) log_rank_p <- sort (log_rank_p) # 取出每一个基因生存分析的P值,形成表 table (log_rank_p < 0.01) # 哪些是P<0.01的 table (log_rank_p < 0.05) # 哪些是P<0.05的 log_rank <- names (log_rank_p)[log_rank_p < 0.05] # log-rank检验筛选的差异基因 |
log-rank批量生存分析结果如下:
KM曲线的优势:可以直接从图中看出组间差异。
KM曲线的局限性:1.无法得知暴露因素对结局的影响是非暴露组多少倍;2.没有控制其他变量。
Cox比例风险回归分析的优势在于可以分析分类变量与数值变量,并且将生存分析的范围由单因素拓展到多因素的分析。
Cox比例风险回归模型可以同时分析几个因素的生存。另外,统计模型提供每个因素的效果大小。
Cox比例风险回归
Cox比例风险回归模型可以分析多个因素对生存事件的影响,而且允许有删失。是生存分析中重要的多因素分析方法。
Cox回归本质上是一种回归模型,它没有直接使用生存时间,而是使用了风险比(hazard ratio)作为因变量。
该模型不用于估计生存率,而是用于因素分析,也就是找到某一个危险因素对结局事件发生的贡献度。
Cox回归的重要统计指标:风险比(hazard ratio,HR),表示变量X变化一个单位引起风险的变化。
当HR > 1时,说明研究对象是一个危险因素。
当HR < 1时,说明研究对象是一个保护因素。
当HR = 1时,说明研究对象对生存时间不起作用。
Cox批量单因素生存分析 Univariate Cox Analysis
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | mySurv <- with (meta, Surv (time, event == "1" )) # 创建生存对象,event = 1表示“1为结局事件发生” unicox_results <- pbapply (exprSet, 1, function (gene){ # 对表达矩阵exprSet中的每一行(基因)执行函数function # gene = as.numeric(exprSet[1,]) # 举个例子 group <- ifelse (gene > median (gene), "high" , "low" ) # 标记不同样本中该基因的上下调,将表达量转换为二分类变量 survival_dat <- data.frame (group = group, stage = meta$stage, age = meta$age, gender = meta$gender, gene = gene, # 基因表达量 stringsAsFactors = F) # 选择用于生存分析的数据 # 拟合Cox比例风险回归模型 m : m <- coxph (mySurv ~ gender + age + stage + group, data = survival_dat) # 表达量用二分类变量group # m <- coxph(mySurv ~ group, data = survival_dat) # 表达量用二分类变量group # m <- coxph(mySurv ~ gene, data = survival_dat) # 表达量也可直接使用连续型变量gene # sm <- summary(m) # 看拟合出的Cox比例风险回归模型的参数 # n:总人数。 # number of events:发生结局事件的人数,即死亡人数 # coef(coefficients,回归系数):结果为正(负),表示男性(genderMALE)死亡风险高(低)于女性,或者说有较低(高)的生存概率。 # exp(coef):也称为风险比(HR)。HR = 1: 无影响,HR < 1: 降低风险,HR > 1: 增加风险。 # se(coef):coef的标准误 # z:Wald检验的统计量,z = coef/se(coef),是否具有统计学意义看p值 # Pr(>|z|):p值 # low.95与upper.95表示HR值的95%置信度区间CI,如果95%CI跨越了1,一般就不认为该因素对生存有显著影响。 beta <- coef (m) se <- sqrt ( diag ( vcov (m))) tmp <- round ( cbind (coef = beta, # 模型的偏回归系数β se = se, # 偏回归系数β的标准误 z = beta/se, # Wald检验的统计量 p = 1 - pchisq ((beta/se)^2, 1), # p值,差异的统计学意义 HR = exp (beta), # 风险值,计算公式为exp(coef) HRCILL = exp (beta - qnorm (.975, 0, 1) * se), # HR的95%置信区间低点 HRCIUL = exp (beta + qnorm (.975, 0, 1) * se)), 3) # HR的95%置信区间高点 return (tmp[ "grouplow" ,]) # 分类变量 # return(tmp["gene",]) # 连续型变量 }) unicox_results <- as.data.frame ( t (unicox_results)) table (unicox_results[,4] < 0.01) # p值<0.01的有多少 table (unicox_results[,4] < 0.05) # p值<0.05的有多少 unicox <- rownames (unicox_results)[unicox_results[,4] < 0.05] # Cox单因素分析筛选的差异基因 |
Cox批量单因素生存分析结果如下:
Cox多因素生存分析 Multivariable Cox Analysis
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | mySurv <- with (meta, Surv (time, event == "1" )) # 创建生存对象 survival_dat <- as.data.frame ( t (exprSet)) # 拟合Cox比例风险回归模型 m : m <- coxph (mySurv ~ LINC02185 + AL391845.2 + LINC00858, data = survival_dat) # 表达量用连续型变量 # sm <- summary(m) # 看拟合出的Cox比例风险回归模型的参数 # n:总人数。 # number of events:发生结局事件的人数,即死亡人数 # coef(coefficients,回归系数):结果为正(负),表示男性(genderMALE)死亡风险高(低)于女性,或者说有较低(高)的生存概率。 # exp(coef):也称为风险比(HR)。HR = 1: 无影响,HR < 1: 降低风险,HR > 1: 增加风险。 # se(coef):coef的标准误 # z:Wald检验的统计量,z = coef/se(coef),是否具有统计学意义看p值 # Pr(>|z|):p值 # low.95与upper.95表示HR值的95%置信度区间CI,如果95%CI跨越了1,一般就不认为该因素对生存有显著影响。 beta <- coef (m) se <- sqrt ( diag ( vcov (m))) multicox_results <- round ( cbind (coef = beta, # 模型的偏回归系数β se = se, # 偏回归系数β的标准误 z = beta/se, # Wald检验的统计量 p = 1 - pchisq ((beta/se)^2, 1), # p值,差异的统计学意义 HR = exp (beta), # 风险值,计算公式为exp(coef) HRCILL = exp (beta - qnorm (.975, 0, 1) * se), # HR的95%置信区间低点 HRCIUL = exp (beta + qnorm (.975, 0, 1) * se)), 3) # HR的95%置信区间高点 table (multicox_results[,4] < 0.01) # p值<0.01的有多少 table (multicox_results[,4] < 0.05) # p值<0.05的有多少 multicox <- rownames (multicox_results)[multicox_results[,4] < 0.05] # Cox多因素分析筛选的差异基因 |
取交集
1 | length ( intersect (log_rank, intersect (unicox, multicox))) # 可以取交集用于后续分析,也可任选lr或cox之一进行分析。 |
一些文章:
一些生存分析相关基础概念:生存分析(Survival analysis)的总结整理
Kaplan-Meier曲线原理详解:画说统计 | 生存分析之Kaplan-Meier曲线都告诉我们什么
log-rank检验和Wilcoxon检验的区别:log-rank检验在什么情况下失效?
用R来做KM生存分析详解:R语言-Survival analysis(生存分析)
Cox与KM生存分析及结果解读:Cox与KM生存分析及结果解读
强烈推荐——sthda官网R代码:Cox Proportional-Hazards Model
Cox回归生存分析 - 简书:Cox回归生存分析
R语言实现及结果解读:生存分析的Cox回归模型(比例风险模型)R语言实现及结果解读
【8文合集】全面了解单因素分析和多因素分析:【8文合集】全面了解单因素分析和多因素分析
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)