參考教程:http://www.sthda.com/english/wiki/survival-analysis-basics
假設(shè)有228個(gè)被診斷患有肺癌的病人開(kāi)始長(zhǎng)期的隨訪,如果病人死亡;則隨訪結(jié)束,并記錄生存時(shí)間(從確診到死亡的時(shí)間)。而生存分析Survival Analysis 主要回答三個(gè)方面的問(wèn)題:
(1)病人的第5年生存率是多少?病人總體的中位生存率的時(shí)間可以到多久?
(2)若根據(jù)病人信息(例如性別),將病人分為兩組,那么這兩組的生存率是否有顯著差異?
(3)若有很多病人的臨床信息或者分子特征,其中哪些屬性會(huì)顯著影響病人的生存?
1、基本概念
1.1 event事件與survival time生存時(shí)間
- 在生存分析中,這里的事件一般是指死亡,在廣義的生存分析中,事件可以引申至許多其它含義,例如疾病復(fù)發(fā)等;
如果處理TCGA的數(shù)據(jù),會(huì)發(fā)現(xiàn)有各種各樣的event的定義,可以參考筆記http://www.lxweimin.com/p/f07588bcf22e。本文筆記全篇采用的是死亡作為事件。
- 而生存時(shí)間是指在事件發(fā)生的前提下,從病人確診到死亡的時(shí)間。
1.2 Censor 刪失值
- 在隨訪的過(guò)程中,可能無(wú)法全部病人都可以收集到準(zhǔn)確地生存時(shí)間。
- 一方面由于隨訪項(xiàng)目時(shí)間限制,直至隨訪結(jié)束,病人仍在世;一方面可能在隨訪期間,病人失聯(lián)、或者因其它原因去世等,無(wú)法繼續(xù)隨訪。
-
這樣的數(shù)據(jù)就稱(chēng)之為Censor,而此時(shí)的生存時(shí)間即為所能記錄到的最長(zhǎng)生存時(shí)間。病人的status要么是事件發(fā)生了,要么就是Censor。
2、Kaplan-Meier與Log-rank test
2.1方法簡(jiǎn)介
- Kaplan-Meier簡(jiǎn)單來(lái)說(shuō)是根據(jù)病人的status與survival time計(jì)算、預(yù)估病人在確診后時(shí)間t時(shí)刻的生存率(survival probability)如何。
survivor function關(guān)注的是event事件不發(fā)生的概率;與之相反,之后會(huì)提到的hazard function則主要關(guān)注event事件發(fā)生的概率
- Log-rank test是指將病人分為兩組或者多組的情況下,組間的生存率是否有顯著差異。
一般上述二者同時(shí)分析
2.2 分析R包與示例數(shù)據(jù)
- R包
# install.packages(c("survival", "survminer"))
library("survival") #生存分析
library("survminer") #結(jié)果可視化
- 示例數(shù)據(jù)
lung {survival}
head(lung)
# inst time status age sex ph.ecog ph.karno pat.karno meal.cal wt.loss
# 1 3 306 2 74 1 1 90 100 1175 NA
# 2 3 455 2 68 1 0 90 90 1225 15
# 3 3 1010 1 56 1 0 90 90 NA 15
# 4 5 210 2 57 1 1 90 60 1150 11
# 5 1 883 2 60 1 0 100 90 NA 0
# 6 12 1022 1 74 1 1 50 80 513 0
# inst: Institution code
# time: Survival time in days(*) 生存時(shí)間
# status: censoring status 1=censored, 2=dead(*) 事件是否發(fā)生
# age: Age in years
# sex: Male=1 Female=2
# ph.ecog: ECOG performance score (0=good 5=dead)
# ph.karno: Karnofsky performance score (bad=0-good=100) rated by physician
# pat.karno: Karnofsky performance score as rated by patient
# meal.cal: Calories consumed at meals
# wt.loss: Weight loss in last six months
如果挖掘TCGA的數(shù)據(jù),通常
0
表示存活,1
表示死亡
2.3 survival
分析
- 開(kāi)始分析:按性別將病人分為兩組
fit <- survfit(Surv(time, status) ~ sex, data = lung)
print(fit)
# Call: survfit(formula = Surv(time, status) ~ sex, data = lung)
#
# n events median 0.95LCL 0.95UCL
# sex=1 138 112 270 212 310
# sex=2 90 53 426 348 550
如上,n
表示每組的病人數(shù);events
表示每組有多少病人死亡;median
表示中位生存率所對(duì)應(yīng)的生存時(shí)間;最后兩列表示第三列的95%置信區(qū)間。
res.sum <- surv_summary(fit)
head(res.sum[res.sum$sex==1,])
# time n.risk n.event n.censor surv std.err upper lower strata sex
# 1 11 138 3 0 0.9782609 0.01268978 1.0000000 0.9542301 sex=1 1
# 2 12 135 1 0 0.9710145 0.01470747 0.9994124 0.9434235 sex=1 1
# 3 13 134 2 0 0.9565217 0.01814885 0.9911586 0.9230952 sex=1 1
# 4 15 132 1 0 0.9492754 0.01967768 0.9866017 0.9133612 sex=1 1
# 5 26 131 1 0 0.9420290 0.02111708 0.9818365 0.9038355 sex=1 1
# 6 30 130 1 0 0.9347826 0.02248469 0.9768989 0.8944820 sex=1 1
head(res.sum[res.sum$sex==2,])
# time n.risk n.event n.censor surv std.err upper lower strata sex
# 120 5 90 1 0 0.9888889 0.01117336 1.0000000 0.9674682 sex=2 2
# 121 60 89 1 0 0.9777778 0.01589104 1.0000000 0.9477934 sex=2 2
# 122 61 88 1 0 0.9666667 0.01957401 1.0000000 0.9302835 sex=2 2
# 123 62 87 1 0 0.9555556 0.02273314 0.9990942 0.9139143 sex=2 2
# 124 79 86 1 0 0.9444444 0.02556550 0.9929738 0.8982868 sex=2 2
# 125 81 85 1 0 0.9333333 0.02817181 0.9863173 0.8831956 sex=2 2
- 如上好像沒(méi)有看到
log-rank test
的結(jié)果,即組間生存率差異的顯著性。其實(shí)參看下面的可視化結(jié)果是有的,如果想提取出來(lái)P值的內(nèi)容,可以如下操作:
surv_diff <- survdiff(Surv(time, status) ~ sex, data = lung)
# Call:
# survdiff(formula = Surv(time, status) ~ sex, data = lung)
#
# N Observed Expected (O-E)^2/E (O-E)^2/V
# sex=1 138 112 91.6 4.55 10.3
# sex=2 90 53 73.4 5.68 10.3
#
# Chisq= 10.3 on 1 degrees of freedom, p= 0.001
#雖然如上結(jié)果是有P值的,但是嘗試之后發(fā)現(xiàn)從對(duì)象中只能提取chisq的值,然后再進(jìn)一步轉(zhuǎn)換
p.val = 1 - pchisq(surv_diff$chisq, length(surv_diff$n) - 1)
p.val
# [1] 0.001311165
2.4 survminer
結(jié)果可視化
(1)生存曲線
ggsurvplot(fit,
pval = TRUE, conf.int = TRUE,
risk.table = TRUE)
圖釋
上圖表示:時(shí)間對(duì)應(yīng)的生存率的生存曲線圖,曲線中的短豎線表示在時(shí)間點(diǎn)有缺失值病人。不同顏色表示不同分組,陰影部分表示95%置信區(qū)間;左下角p值表示基于log-rank test計(jì)算得到的P值,對(duì)于本圖的結(jié)果p=0.0013,即不同性別的生存率有顯著差異。
下面的表:不同時(shí)間點(diǎn)對(duì)應(yīng)每組尚未發(fā)生事件(死亡)的數(shù)目。
圖形參數(shù)(結(jié)合具體代碼理解)
p1=ggsurvplot(fit,
pval = TRUE, conf.int = TRUE,
risk.table = TRUE, # Add risk table
risk.table.col = "strata", # Change risk table color by groups
linetype = "strata", # Change line type by groups
surv.median.line = "hv", # Specify median survival
ggtheme = theme_bw(), # Change ggplot2 theme
palette = c("#E7B800", "#2E9FDF"))
p2=ggsurvplot(
fit, # survfit object with calculated statistics.
pval = TRUE, # show p-value of log-rank test.
conf.int = TRUE, # show confidence intervals for
# point estimaes of survival curves.
conf.int.style = "step", # customize style of confidence intervals
xlab = "Time in days", # customize X axis label.
break.time.by = 200, # break X axis in time intervals by 200.
ggtheme = theme_light(), # customize plot and risk table with a theme.
risk.table = "abs_pct", # absolute number and percentage at risk.
risk.table.y.text.col = T,# colour risk table text annotations.
risk.table.y.text = FALSE,# show bars instead of names in text annotations
# in legend of risk table.
ncensor.plot = TRUE, # plot the number of censored subjects at time t
surv.median.line = "hv", # add the median survival pointer.
legend.labs =
c("Male", "Female"), # change legend labels.
palette =
c("#E7B800", "#2E9FDF") # custom color palettes.
)
arrange_ggsurvplots(list(p1,p2))
(2)其它類(lèi)型曲線
- 參數(shù)
fun="event"
,表示cumulative event事件累計(jì)發(fā)生率
p3=ggsurvplot(fit,
conf.int = TRUE,
risk.table.col = "strata", # Change risk table color by groups
ggtheme = theme_bw(), # Change ggplot2 theme
palette = c("#E7B800", "#2E9FDF"),
fun = "event")
- 參數(shù)
fun="cumhaz"
,表示cummulative hazard表示累計(jì)風(fēng)險(xiǎn)水平(在時(shí)刻t,事件發(fā)生的可能性)
p4=ggsurvplot(fit,
conf.int = TRUE,
risk.table.col = "strata", # Change risk table color by groups
ggtheme = theme_bw(), # Change ggplot2 theme
palette = c("#E7B800", "#2E9FDF"),
fun = "cumhaz")
arrange_ggsurvplots(list(p3,p4))
3、Cox Proportional-Hazards Model比例風(fēng)險(xiǎn)模型
3.1 簡(jiǎn)單理解
- 上面了解的log-rank test用于比較兩個(gè)分組的生存率是否有顯著差異,從而反映出這個(gè)分組因子的意義。但由于必須要分組,所以必須使用分類(lèi)變量,或者將連續(xù)變量(基因表達(dá))轉(zhuǎn)為分組變量(中位數(shù)劃分)。
- 而這里的Cox Proportional-Hazards Model可以理解為回歸模型。其中回歸模型的響應(yīng)變量Y是Hazard rate(風(fēng)險(xiǎn)因子,可以類(lèi)比死亡率);而預(yù)測(cè)變量就是想驗(yàn)證是否會(huì)影響病人生存率的臨床特征、基因表達(dá)等變量(分類(lèi)變量、連續(xù)變量均可)。通過(guò)P值反映變量是否有顯著影響;通過(guò)變量的系數(shù)coefficient表征如何影響Hazard rate,更常用的形式為:Hazard ratio(HR)=exp(coef);如果HR<1(coef<0),則表明該變量越大,風(fēng)險(xiǎn)越低,生存率越高;HR>1(coef>0),則表明該變量越大,風(fēng)險(xiǎn)越高,生存率越小。
3.2 單變量Cox回歸
res.cox <- coxph(Surv(time, status) ~ sex, data = lung)
res.cox
# Call:
# coxph(formula = Surv(time, status) ~ sex, data = lung)
#
# coef exp(coef) se(coef) z p
# sex -0.5310 0.5880 0.1672 -3.176 0.00149
#
# Likelihood ratio test=10.63 on 1 df, p=0.001111
# n= 228, number of events= 165
exp(res.cox$coefficients)
# sex
# 0.5880028
- 對(duì)多個(gè)變量分別進(jìn)行單變量Cox回歸
#分別回歸
covariates <- c("age", "sex", "ph.karno", "ph.ecog", "wt.loss")
univ_formulas <- sapply(covariates,
function(x) as.formula(paste('Surv(time, status)~', x)))
univ_models <- lapply( univ_formulas, function(x){coxph(x, data = lung)})
#提取各個(gè)變量的回歸結(jié)果
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)
# beta HR (95% CI for HR) wald.test p.value
# age 0.019 1 (1-1) 4.1 0.042
# sex -0.53 0.59 (0.42-0.82) 10 0.0015
# ph.karno -0.016 0.98 (0.97-1) 7.9 0.005
# ph.ecog 0.48 1.6 (1.3-2) 18 2.7e-05
# wt.loss 0.0013 1 (0.99-1) 0.05 0.83
3.3 多變量Cox回歸(多元回歸)
res.cox <- coxph(Surv(time, status) ~ age + sex + ph.ecog, data = lung)
summary(res.cox)
# Call:
# coxph(formula = Surv(time, status) ~ age + sex + ph.ecog, data = lung)
#
# n= 227, number of events= 164
# (因?yàn)椴淮嬖冢?個(gè)觀察量被刪除了)
#
# coef exp(coef) se(coef) z Pr(>|z|)
# age 0.011067 1.011128 0.009267 1.194 0.232416
# sex -0.552612 0.575445 0.167739 -3.294 0.000986 ***
# ph.ecog 0.463728 1.589991 0.113577 4.083 4.45e-05 ***
# ---
# Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
#
# exp(coef) exp(-coef) lower .95 upper .95
# age 1.0111 0.9890 0.9929 1.0297
# sex 0.5754 1.7378 0.4142 0.7994
# ph.ecog 1.5900 0.6289 1.2727 1.9864
#
# Concordance= 0.637 (se = 0.025 )
# Likelihood ratio test= 30.5 on 3 df, p=1e-06
# Wald test = 29.93 on 3 df, p=1e-06
# Score (logrank) test = 30.5 on 3 df, p=1e-06
ggforest(res.cox, data = lung,
main = "Hazard ratio",
cpositions = c(0.10, 0.22, 0.4),
fontsize = 1.0)
3.4 注意點(diǎn)
(1)如果多變量cox回歸結(jié)果證明多個(gè)變量均影響Hazard rate,那么當(dāng)想要觀察其中一個(gè)變量所造成分組的生存率差異(KM plot)時(shí),需要其它變量的值拉到統(tǒng)一水平(均值)
(2)Cox回歸一個(gè)重要的假設(shè),就是變量對(duì)于hazard rate的影響不隨時(shí)間的變化而變化(等比例),可通過(guò)統(tǒng)計(jì)方法檢驗(yàn)變量數(shù)據(jù)是否適合Cox回歸分析。詳見(jiàn) http://www.sthda.com/english/wiki/cox-model-assumptions