列线图(Alignment Diagram),也称诺莫图(Nomogram),绝是临床预测模型最为常见的一种呈现形式。列线图可以根据受试者的一些特征(解释变量)来预测结局事件的发生概率或者患者的生存率等。生存资料预测模型的列线图除了可以预测生存率,还可以预测分位数生存时间、生存时间期望均值、风险比。
生存资料预测模型的构建绝大多数是基于COX回归法。COX回归属于半参数法,在多因素的生存分析中几乎是霸主般的存在,主要是因为COX回归几乎不需要考虑前提条件,仅要求满足比例风险假定就可以了。除了COX回归,参数生存模型也是生存资料非常重要的分析方法。但参数法需要数据满足一定分布,一说到分布啥的一些理论,基本上就阻断了大部分人继续下去的欲望,甚至头皮发麻恶心想吐,哪还有心思去搞清楚怎么用。但其实如果满足适用条件,参数法可能会比非参数法更好地解释数据。正如在比较组间效应时,如果数据满足独立正态同方差,我们更愿意适用t检验/方差分析,而不会首选非参数检验一样,虽然使用非参数检验也没有错。与生存时间相关的一些重要分布有"weibull", "exponential", "gaussian", "logistic","lognormal" and "loglogistic"。
此次笔记的任务就是绘制生存资料预测模型的列线图,包括COX回归模型和参数生存模型。
下面直接上命令清单:
导入数据与因子设置
##导入数据
##设置因子及因子各水平的标签
##载入列线图绘制程序包
library(rms)
library(Hmisc);library(lattice);library(survival);library(Formula);library(ggplot2);library(SparseM)
CoxNM<-datadist(HF)
options(datadist='CoxNM')
label(HF$Age.cat)<-"Age"
label(HF$EF)<-"Ejection Fraction"
label(HF$SCr.cat)<-"Serum Creatinine"
##建立COX回归模型
HFDeath.cox<-cph(Surv(Time,Death==1)~Age.cat+EF+SCr.cat,data=HF,x=T,y=T,surv=T,method="breslow")
#method:结(ties)的处理方式有efron、breslow和exact,默认为efron。这里改为method="breslow"是为了得到跟SPSS一致的结果,STATA默认的也是breslow。同样的数据在采用R的coxph{survival}和cph{rms}的进行Cox回归,其结果与SPSS有略微差异,如果你像我一样纠结,可以在R中把结的处理方式改一下就可以了;
#x、y、surv:这几个参数是为了绘制后面的列线图方便,都设置为TRUE就可以了;
#time.inc:这在后期进行模型评估中可能会用到,比如评估模型在不同时间点上的校准度,常常用函数calibrate绘制1年、3、5年的校准曲线,这时候就需要用time.inc指定时间点,然后再calibrate函数的u参数进行呼应。
##建立生存率的估计函数
surv<-Survival(HFDeath.cox)
surv3M<-function(x)surv(91.31,lp=x)
surv0.5<-function(x)surv(182.625,lp=x)
surv1<-function(x)surv(285,lp=x)
#Survival函数可以对cph创建的对象返回一个S函数,用于计算生存率的估计值。除了Survival函数,Quantile()返回的S函数可用于计算生存时间的分位数(默认为中位数,可通过q来指定具体的分位数);Mean()返回返回一个计算平均生存时间的函数。参数估计模型还有Hazard()用于估计风险函数;
#通过function函数定义了三个生存率的计算函数,这些函数以一个时间点和线性预测器作为参数,并返回该时间点的生存率。本例时间单位是天,用91.31天和182.62天来表示1个月和3个月,1年应该用365.25天,但本例最长的随访时间是285天,如果使用大于285的数字,结果会报错“Error in approx(fu[s], xseq[s], fat, ties = mean) :调用内插至少需要两个非NA值的数”。此处仅示例。
Nom.Surv<-nomogram(HFDeath.cox,lp=T,fun=list(surv3M,surv0.5,surv1), fun.at=c('0.99','0.95','0.90','0.85',seq(0.80,0.10,by=-0.1),'0.05','0.01'),funlabel=c("3-Month Survival Prob.","Half-Year Survival Prob.","1-Year Survival Prob."))
##列线图绘制的主要函数,参数又多又复杂又难理解,仅介绍几个常用的、重要的
#lp:默认设置为FALSE,即不显示线性预测器(linear predictor)的那条坐标轴。我们最终想预测的概率就是这个线性预测器的值通过一定的函数变换得来的。列线图的基本原理就是根据预测变量对结局的影响大小(回归系数),给各个预测变量的水平进行赋分,评分之和通过函数转化成结局事件发生概率。这个线性预测值可以理解为承接变量总评分与预测概率之间的中间变量,对列线图的使用而言其实没啥毛用;
#fun:对线性预测值进行转换的函数;
#fun.at:预测值横轴的刻度,本例是在坐标轴上显示的概率值。可使用该参数的默认值,也可通过该参数改成需要显示的值。同一个fun函数可以是使用同一个fun.at向量值,不同fun函数需要用fun.at值的向量列表标识。本例有三个自建函数,不过都是对应生成生存率的Survival这一个函数,因此三条预测概率坐标轴刻度使用了相同的fun.at值;
#funlabel:预测横轴名称,默认"Predicted Value";
#conf.int: 是否显示得分的置信区间,默认否;
#maxscale:默认单变量最大分数值是100分。
plot(Nom.Surv,xfrac=.25,col.grid=gray(c(0.8,0.95)))
##主要是将前面Nomogram函数的结果画出来,一些参数可以起到美化作用
#lplabel:线性预测器横轴的名称,默认"Linear Predictor"。不过这个变量我一般会在Nomogram中关掉不显示;
#fun.side:预测轴上的刻度值位置,1用于定位在轴下方(默认值),3用于轴上方。预测横轴的刻度值有时候会非常拥挤甚至重叠在一起,如一个轴有5个标记标签值,第二个和第三个相互重叠,可该参数进行指定:fun.side=c(1,1,3,1,1);
#col.conf:置信区间的颜色设置;
#xfrac:各刻度线横轴与轴名称之间的空白间隔所占的比例,默认0.35。如果你觉得坐标轴名称与坐标轴隔得距离太远,可以把这个值设置的小一些;
#cex.axis:刻度轴刻度标签的字符大小,默认0.85;
#cex.var:刻度轴名称的字符大小,默认1;刻度轴标题默认是变量名称,可通过label()进行修改;
#col.grid :默认不绘制垂直参考网格线。该参数若长度为1,则对主要和次要参考线使用相同的颜色,长度为2则分别对应主要和次要参考线的颜色,常用灰色col.grid = gray(c(0.8, 0.95));
#points.label:单变量评分轴的名称,默认为'Points';
#total.points.label:总评分轴的名称,默认'Total Points'。
1.2.2带有交互作用的列线图绘制
模型是否存在交互作用应在1.2步进行考察,此处仅演示其列线图的绘制操作。
HFDeath.cox2<-cph(Surv(Time,Death==1)~Age.cat+EF+SCr.cat+Age.cat*EF,data=HF,x=T,y=T,surv=T,method="breslow")
mea<-Mean(HFDeath.cox2)
surv3M<-function(x)surv(91.31,lp=x)
surv0.5<-function(x)surv(182.625,lp=x)
surv1<-function(x)surv(285,lp=x)
mean<-function(x)mea(lp=x)
#除了建立生存率预测函数,还建立一个生存时间期望均值的预测函数。最后一次随访时结局为非删失事件,Mean函数会有报警。由于删失的存在,平均生存时间是一个有偏估计量,一般用生存曲线下面积或累计发病率曲线上面积表示。
#此处本来还想演示一下fun.side参数的:fun.side=list(rep(1,10),rep(3,10),rep(c(1,3),5),c(rep(1,10),3,1,3,1)),结果报错。单独预测生存率或者单独预测生存时间均值时都没有问题,但合在一起就出现了错误,寻因良久,未果,只得作罢。不过可以适当对fun.at参数进行调整来解决刻度值拥挤的问题。
#dist:可选择的分布有weibull, exponential、gaussian、logistic、lognormal和loglogistic
quan<-Quantile(HFDeath.psm)
surv100D<-function(x)surv(100,lp=x)
surv0.5<-function(x)surv(182.625,lp=x)
surv1<-function(x)surv(285,lp=x)
Q25<-function(x)quan(lp=x,q=0.25)
median<-function(x)quan(lp=x)
#除了建立生存率预测函数,同时建立生存时间分位数的预测函数。默认是中位值,通过q参数可指定任意分位数
#本例25分位数生存时间为100天,随访结束时的累积生存率为57.6%,尚未到达中位生存时间
#采用默认的fun.at,分位数预测刻度轴的标签会非常得拥挤,但在调整展示两个函数(此处是生存函数和分为数函数)刻度值的位置时,fun.side参数再次报错,只能使用fun.at可以进行适当的调整。
Nom.Quan.psm<-nomogram(HFDeath.psm,lp=F,fun=list(Q25,median), fun.at=c(seq(20,100,by=20),seq(150,300,by=50),seq(400,1200,by=200),1800,2500), funlabel=c("Q25 Survival Time","Q50 Survival Time"))
rms包帮助文件:https://cran.r-project.org/web/packages/rms/
Zhongheng Zhang,Michael W. Kattan.Drawing Nomograms with R: applications to categorical outcome and survival data.Ann Transl Med 2017;5(10):211. [http://dx.doi.org/10.21037/atm.2017.04.01]
END
联系客服