题记:我们在以前的文章中介绍了竞争风险模型的R语言实现,今天我们与各位朋友分享如何基于竞争风险模型绘制列线图,以飨读者。
1. 背景知识
在观察某事件是否发生时,如果该事件被其他事件阻碍,即存在所谓“竞争风险”。研究中结局事件可能有多个,某些结局将阻止感兴趣事件的出现或影响其发生的概率,各结局事件形成“竞争”关系,互为竞争风险事件。
举例来说,某研究人员收集了本市2007年确诊为轻度认知损害(MCI)的518例老年患者临床资料,包括基本人口学特征、生活方式、体格检查和合并疾病信息等,并于2010~2013年完成6次随访调查,主要观察结局为发生阿尔兹海默病(AD)。随访期间,共发生AD78例,失访84例,其中28例搬迁、31例退出、25例死亡。试问影响MCI向AD转归的因素都有哪些?本例中,如果MCI患者在观察期间死于癌症、心血管疾病、车祸等原因而未发生AD,就不能为AD的发病做出贡献,即死亡“竞争”了AD的发生。传统生存资料统计方法将发生AD前死亡的个体、失访个体和未发生AD个体均按删失数据(censored data)处理,可能会导致估计偏差[1]。对于死亡率较高的老年人群,当有竞争风险事件存在时,采用传统生存分析方法(K-M法、Cox比例风险回归模型)会高估所研究疾病的发生风险,产生竞争风险偏倚,有人专门研究发现约46%的文献可能存在这种偏倚。
本例中若选用竞争风险模型处理较为恰当。所谓竞争风险模型(Competing Risk Model)是一种处理多种潜在结局生存数据的分析方法,早在1999年Fine和Gray就提出了部分分布的半参数比例风险模型,通常使用的终点指标是累积发生率函数(Cumulative incidence function,CIF)[1-2]。本例中可以将发生AD前死亡作为AD的竞争风险事件,采用竞争风险模型进行统计分析。竞争风险的单因素分析常用来估计关心终点事件的发生率,多因素分析常用来探索预后影响因素及效应值。
2. 案例分析
2.1 [案例分析]
本案例数据来自http://www.stat.unipg.it/luca/R/。有研究者探讨骨髓移植对比血液移植治疗白血病的疗效,结局事件定义为“复发”,某些患者移植后不幸因为移植不良反应死亡,那这些发生移植相关死亡的患者就无法观察到“复发”的终点,也就是说“移植相关死亡”与“复发”存在竞争风险。故采用竞争风险模型分析[3-4]。
首先从当前工作路径中导入数据文件’bmtcrr.csv’。
<pre style="box-sizing: inherit; border: 1px solid rgb(209, 209, 209); font-family: inherit; font-size: 16px; font-style: normal; margin: 0px 0px 5px; padding: 15px; vertical-align: baseline; line-height: 30.4px; max-width: 100%; overflow: auto; white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">library(foreign)
bmt <-read.csv('bmtcrr.csv')
str(bmt)</pre>
<pre style="box-sizing: inherit; border: 1px solid rgb(209, 209, 209); font-family: inherit; font-size: 16px; font-style: normal; margin: 0px 0px 5px; padding: 15px; vertical-align: baseline; line-height: 30.4px; max-width: 100%; overflow: auto; white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">## 'data.frame': 177 obs. of 7 variables:
$ Sex : Factor w/ 2 levels "F","M": 2 1 2 1 1 2 2 1 2 1 ...
$ D : Factor w/ 2 levels "ALL","AML": 1 2 1 1 1 1 1 1 1 1 ...
$ Phase : Factor w/ 4 levels "CR1","CR2","CR3",..: 4 2 3 2 2 4 1 1 1 4 ...
$ Age : int 48 23 7 26 36 17 7 17 26 8 ...
$ Status: int 2 1 0 2 2 2 0 2 0 1 ...
$ Source: Factor w/ 2 levels "BM+PB","PB": 1 1 1 1 1 1 1 1 1 1 ...
$ ftime : num 0.67 9.5 131.77 24.03 1.47 ...</pre>
这是一个数据框结构的数据,含有7个变量,共177个观测。
$ Sex : 因子变量,2个水平:“F”,“M”。
$ D : 因子变量,2个水平:“ALL(急性淋巴细胞白血病)”,“AML(急性髓系细胞白血病)”。
$ Phase : 因子变量,4个水平:“CR1”,“CR2”,“CR3”,“Relapse”。
$ Age : 年龄。
$ Status: 结局,0=删失,1=复发,2=竞争风险事件。
$ Source: 因子变量,2个水平:“BM+PB(骨髓移植+血液移植)”,“PB(血液移植)”。
$ ftime : 时间。
在R中加载竞争风险模型的程辑包cmprsk,使用cuminc()函数及crr()函数即可进行考虑竞争风险事件生存资料的单因素分析与多因素分析,我们在前文已经详细述及基于R语言实现的方式,此处不表。
如何对竞争风险模型进行可视化?如何绘制列线图?
下面我们基于R演示如何绘制竞争风险模型的列线图。
首先,对数据集bmt中的变量进行进一步处理。
<pre style="box-sizing: inherit; border: 1px solid rgb(209, 209, 209); font-family: inherit; font-size: 16px; font-style: normal; margin: 0px 0px 5px; padding: 15px; vertical-align: baseline; line-height: 30.4px; max-width: 100%; overflow: auto; white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">bmtage <- bmtsex <- as.factor(ifelse(bmtD <- as.factor(ifelse(bmtphase_cr <- as.factor(ifelse(bmtsource = as.factor(ifelse(bmt$Source=='PB',1,0))</pre>
查看数据结构,并展示前6行。我们对数据集中的协变量重新进行了赋值,并对多分类变量进行了二值化。注意,此处多分类变量我们并未设置哑变量,主要考量是:在列线图中如果出现哑变量的情形,结果解读会让人困惑,所以列线图中应避免哑变量的情形,可考虑根据专业知识将多分类变量按照等级资料处理或者二值化。
<pre style="box-sizing: inherit; border: 1px solid rgb(209, 209, 209); font-family: inherit; font-size: 16px; font-style: normal; margin: 0px 0px 5px; padding: 15px; vertical-align: baseline; line-height: 30.4px; max-width: 100%; overflow: auto; white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">str(bmt)</pre>
<pre style="box-sizing: inherit; border: 1px solid rgb(209, 209, 209); font-family: inherit; font-size: 16px; font-style: normal; margin: 0px 0px 5px; padding: 15px; vertical-align: baseline; line-height: 30.4px; max-width: 100%; overflow: auto; white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">## 'data.frame': 177 obs. of 12 variables:
$ Sex : Factor w/ 2 levels "F","M": 2 1 2 1 1 2 2 1 2 1 ...
$ D : Factor w/ 2 levels "0","1": 1 2 1 1 1 1 1 1 1 1 ...
$ Phase : Factor w/ 4 levels "CR1","CR2","CR3",..: 4 2 3 2 2 4 1 1 1 4 ...
$ Age : int 48 23 7 26 36 17 7 17 26 8 ...
$ Status : int 2 1 0 2 2 2 0 2 0 1 ...
$ Source : Factor w/ 2 levels "BM+PB","PB": 1 1 1 1 1 1 1 1 1 1 ...
$ ftime : num 0.67 9.5 131.77 24.03 1.47 ...
$ id : int 1 2 3 4 5 6 7 8 9 10 ...
$ age : int 48 23 7 26 36 17 7 17 26 8 ...
$ sex : Factor w/ 2 levels "0","1": 1 2 1 2 2 1 1 2 1 2 ...
$ phase_cr: Factor w/ 2 levels "0","1": 2 1 1 1 1 2 1 1 1 2 ...
$ source : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...</pre>
<pre style="box-sizing: inherit; border: 1px solid rgb(209, 209, 209); font-family: inherit; font-size: 16px; font-style: normal; margin: 0px 0px 5px; padding: 15px; vertical-align: baseline; line-height: 30.4px; max-width: 100%; overflow: auto; white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">head(bmt)</pre>
<pre style="box-sizing: inherit; border: 1px solid rgb(209, 209, 209); font-family: inherit; font-size: 16px; font-style: normal; margin: 0px 0px 5px; padding: 15px; vertical-align: baseline; line-height: 30.4px; max-width: 100%; overflow: auto; white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">## Sex D Phase Age Status Source ftime id age sex phase_cr source
1 M 0 Relapse 48 2 BM+PB 0.67 1 48 0 1 0
2 F 1 CR2 23 1 BM+PB 9.50 2 23 1 0 0
3 M 0 CR3 7 0 BM+PB 131.77 3 7 0 0 0
4 F 0 CR2 26 2 BM+PB 24.03 4 26 1 0 0
5 F 0 CR2 36 2 BM+PB 1.47 5 36 1 0 0
6 M 0 Relapse 17 2 BM+PB 2.23 6 17 0 1 0</pre>
regplot包中的regplot()函数可绘制较为美观的nomogram。但是,它目前只接收coxph()、lm()和glm()函数返回的回归对象。因此,为了绘制竞争风险模型的nomogram,我们需要对原数据集加权创建一个新数据集用于为竞争风险模型分析[5-6]。mstate包中的crprep()函数的功能主要在于创建此加权数据集,如下面的R代码所示。然后,我们就可以使用coxph()函数对加权数据集进行竞争风险模型拟合,然后传递给regplot()来绘制nomogram。具体加权原理读者可参考Geskus RB等人发表的文献[5],此处不表。
下面,我们对原数据集bmt创建加权数据集并命名为df.w。其中,参数trans=指定需要加权计算的终点事件与竞争风险事件;cens=指定截尾;id=传入数据集bmt的id;keep=数据集中需要保留的协变量。
<pre style="box-sizing: inherit; border: 1px solid rgb(209, 209, 209); font-family: inherit; font-size: 16px; font-style: normal; margin: 0px 0px 5px; padding: 15px; vertical-align: baseline; line-height: 30.4px; max-width: 100%; overflow: auto; white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">library(mstate)</pre>
<pre style="box-sizing: inherit; border: 1px solid rgb(209, 209, 209); font-family: inherit; font-size: 16px; font-style: normal; margin: 0px 0px 5px; padding: 15px; vertical-align: baseline; line-height: 30.4px; max-width: 100%; overflow: auto; white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">## Loading required package: survival</pre>
<pre style="box-sizing: inherit; border: 1px solid rgb(209, 209, 209); font-family: inherit; font-size: 16px; font-style: normal; margin: 0px 0px 5px; padding: 15px; vertical-align: baseline; line-height: 30.4px; max-width: 100%; overflow: auto; white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">df.w <- crprep("ftime", "Status",
data=bmt, trans=c(1,2),
cens=0, id="id",
keep=c("age","sex","D","phase_cr","source"))
df.wTstop - df.w$Tstart</pre>
上述代码已经创建一个加权数据集df.w,然后我们可以在此数据集上使用coxph()函数进行竞争风险分析。
<pre class="" style="box-sizing: inherit; border: 1px solid rgb(209, 209, 209); font-family: inherit; font-size: 16px; font-style: normal; margin: 0px 0px 5px; padding: 15px; vertical-align: baseline; line-height: 30.4px; max-width: 100%; overflow: auto; white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">m.crr<- coxph(Surv(T,status==1)~age+sex+D+phase_cr+source,
data=df.w,
weight=weight.cens,
subset=failcode==1)
summary(m.crr)</pre>
<pre style="box-sizing: inherit; border: 1px solid rgb(209, 209, 209); font-family: inherit; font-size: 16px; font-style: normal; margin: 0px 0px 5px; padding: 15px; vertical-align: baseline; line-height: 30.4px; max-width: 100%; overflow: auto; white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">## Call:
coxph(formula = Surv(T, status == 1) ~ age + sex + D + phase_cr +
source, data = df.w, weights = weight.cens, subset = failcode ==
1)
n= 686, number of events= 56
coef exp(coef) se(coef) z Pr(>|z|)
age -0.02174 0.97850 0.01172 -1.854 0.06376 .
sex1 -0.10551 0.89987 0.27981 -0.377 0.70612
D1 -0.53163 0.58764 0.29917 -1.777 0.07556 .
phase_cr1 1.06140 2.89040 0.27870 3.808 0.00014 ***
source1 1.06564 2.90269 0.53453 1.994 0.04620 *
---
Signif. codes: 0 '' 0.001 '' 0.01 '' 0.05 '.' 0.1 ' ' 1
exp(coef) exp(-coef) lower .95 upper .95
age 0.9785 1.0220 0.9563 1.001
sex1 0.8999 1.1113 0.5200 1.557
D1 0.5876 1.7017 0.3269 1.056
phase_cr1 2.8904 0.3460 1.6739 4.991
source1 2.9027 0.3445 1.0181 8.275
Concordance= 0.737 (se = 0.037 )
Likelihood ratio test= 28.33 on 5 df, p=3e-05
Wald test = 28.54 on 5 df, p=3e-05
Score (logrank) test = 30.49 on 5 df, p=1e-05</pre>
接下来,我们可以使用regplot()函数绘制nomogram。在nomogram中,将数据集中id=31的患者各协变量的取值映射到相应的得分,并计算总得分,并分别计算其在36个月和60个月的累计复发概率,此概率即为控制了竞争风险的累计复发概率,分别为:0.196和0.213。
<pre style="box-sizing: inherit; border: 1px solid rgb(209, 209, 209); font-family: inherit; font-size: 16px; font-style: normal; margin: 0px 0px 5px; padding: 15px; vertical-align: baseline; line-height: 30.4px; max-width: 100%; overflow: auto; white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">library(regplot)
regplot(m.crr,observation=df.w[df.wfailcode==1,],
failtime = c(36, 60), prfail = T, droplines=T)</pre>
<pre style="box-sizing: inherit; border: 1px solid rgb(209, 209, 209); font-family: inherit; font-size: 16px; font-style: normal; margin: 0px 0px 5px; padding: 15px; vertical-align: baseline; line-height: 30.4px; max-width: 100%; overflow: auto; white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">## Replicate weights assumed</pre>
<pre style="box-sizing: inherit; border: 1px solid rgb(209, 209, 209); font-family: inherit; font-size: 16px; font-style: normal; margin: 0px 0px 5px; padding: 15px; vertical-align: baseline; line-height: 30.4px; max-width: 100%; overflow: auto; white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">## Click on graphic expected. To quit click Esc or press Esc</pre>
<pre style="box-sizing: inherit; border: 1px solid rgb(209, 209, 209); font-family: inherit; font-size: 16px; font-style: normal; margin: 0px 0px 5px; padding: 15px; vertical-align: baseline; line-height: 30.4px; max-width: 100%; overflow: auto; white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;"># $points.tables
网友评论