作者:麦子
转载请注明:解螺旋·临床医生科研成长平台
诺莫图(Nomogram)又称列线图(Alignment Chart),是把数学公式画成图的表达方法,我好像只能解释到这了……
不管了,先看个例子,来自Lancet Neurol. 2017 Jul;16(7):532-540.
这是收集了900多例轻度外伤性脑损伤(mTBI)患者的几个临床信息,如图第二行开始,包括教育程度、精神健康状况、饮酒史等等,一直到Total Points以上。结局指标为6个月后是否完全康复(GOSE评分≤7为不完全,GOSE=8为完全)。
然后做个logistic回归,建立模型,通过这几个指标预测不完全康复的风险。一般我们做logistic也就是想看看哪几个指标对结局影响比较大,但具体到患者个人来说,我有个高风险指标,但我怎么知道发生结局事件的风险是多少呢?
这时就可以通过这种图来计算,取得那几个指定的临床信息(自变量)后,从该自变量的坐标轴向顶部的points轴作一条垂直线,得到对应的point,第个自变量的point相加得到总分,在下方的total points上找到对应的值,向下边的linear predictor(线性预测值)再作一条垂直线,即得到发生结局事件的风险,更有临床应用的价值。
这个线性预测跟我们熟悉的风险概率不太一样,但其实可以转换的。
纪念斯隆凯特琳癌症研究所好像特别推崇这种方法,建立了好几种癌症的预测模型,而这种表达方式也渐渐在各大期刊流行起来。想学不?正好这里有一篇新鲜教程,由浙大医学院和克利夫兰医学基金会的老师们合作发表(Ann Transl Med. 2017 May; 5(10): 211.),一起来研习一下吧。
载入所需要的包
library(rms)
这个包还需预先载入Hmisc、survival、Formula、ggplot2,如果系统没有自动载入,还请自行手动安装并载入。
构建示例数据
这段大概看一下知道数据是怎么来的就行了,反正你的实验数据是不需要构建的。
接下来看看生成的表格,数据结构是这个样子(显示部分):
年龄和乳酸水平为连续变量,性别为二元变量,卒中为分类变量,有四个level,分别为No、Mild、Moderate(未展示)、Severe。结局指标y为二元变量,1表示死亡。接下来用logistic回归,通过三个自变量预测死亡风险。
打包数据
ddist <- datadist(data)
options(datadist = 'ddist')
因为我们不仅是要做logistic回归,还要做列线图,这一步是专为列线图而设的。用datadist()定义各变量的分布,再把它们包到options()中。运行ddist可以看到输出结果:
包含各变量的描述信息,范围。一会作图就会默默地使用这些值。
Logistic回归
mod <- lrm(y~shock+lac*sex+age,data)
“~”前面是结局,后面是自变量,各自变量用+相连。乳酸一项需要根据性别分层,所以乳酸和性别用*号,后面的data是用到的数据集。
设置列线图参数
nom <- nomogram(mod,
lp=T,
lp.at = seq(-3,4,by=0.5),
fun=function(x) 1/(1+exp(-x)),
funlabel = 'Risk of Death',
fun.at = c(0.05,seq(0.1,0.9,by=0.1),0.95),
conf.int = c(0.1,0.7))
第一行mod就是刚才logistic回归的模型名称。Lp选择True或False,是否显示线性预测坐标(linear predictor),lp.at则是设置其坐标轴的范围,此处就是从-3到4,每个刻度为0.5。
fun是要自己设一个函数,对lp进行转换,并建立一个新坐标轴。此处就用logit变换的反函数,将lp转换为我们熟悉的风险概率-。function(x) 1/(1+exp(-x))这一串,即使用function()构建一个自定义函数,括号中的x从lp的范围中取值,代入1/(1+exp(-x))中运算。
fun.at则是给新的坐标轴设置范围。本例中,lp的最小值是-3,对应的死亡风险是0.0474,所以起始值要大于这个值才能显示,不落在其范围内的都是不会显示的。
funlabel则是给上面转换好的新坐标轴起个名字,Risk of Death。其实有了这条坐标轴,上面lp那里也可以设为F,不显示了。但即使不显示,lp.at还是要设置,否则光设后面的fun.at似乎是无效的。
conf.int展示每个自变量坐标轴上各刻度的置信区间,这里显示两层置信区间,即0.1和0.7。默认是F,即不显示。其实好多文章都不显示,你可以多学一招。
出图
plot(nom,
lplabel = 'Linear Predictor',
fun.side = c(1,1,1,1,3,1,3,1,1,1,1),
label.every = 3,
col.conf = c('red','green'),
conf.space = c(0.1,0.5),
col.grid = gray(c(0.8,0.95)),
which='shock')
用plot()作图。nom是刚才定义的所有参数对象的名字,lplabel是lp坐标轴的名称,如果刚才lp选了F,这行也可以不要了。
fun.side是设置新坐标轴“Risk of Death”的坐标刻度显示在哪一边,1表示下方,3为上方。不写则默认下方,但当空间比较窄,刻度密集时,可以把几个刻度放到上面。刚才fun.at设了几个刻度,这里的fun.side就要设几个值。数不清的话,可以把fun.at那一行单独选中运行一次,然后运行length(fun.at)查看。
label.every也是这个意思,刻度每3个显示1个,拒绝密恐。
col.conf设置置信区间的颜色。传说“红配绿赛狗屁”不是没有道理,忘了是Nat Commum.还是哪个杂志来着,建议作者们不要使用红绿配色,照顾色盲同学。。。
conf.space是设置刚才那些置信区间条在两条坐标轴之间的位置,两轴之间的距离为1,现在设成0.1~0.5之间,虽然设了看起来不精确,但不设会压成一团。
col.grid设置垂直参考线的颜色,从自变量轴指向point轴。一般设2个,表示主要和次要刻度。此处表示灰色的0.8透明度和0.95透明度,你也可以设成其他颜色,格式同上面的红配绿。
终于看到图了!
是不是比那个Lancet Neurology的例子还丰富一些^_^
列线图不仅能画出logistic模型,我们常用的cox模型、生存模型等等都可绘制,有兴趣的同学可参考原教程,应该能触类旁通了~
参考文献:
1.Early predictors of outcome after mild traumatic brain injury (UPFRONT): an observational cohort study
2.Drawing Nomograms with R: applications to categorical outcome and survival data