我会推荐Hanley和McNeil在1982年发表的论文“ 接收机工作特性(ROC)曲线下面积的含义和使用 ”。
例
它们具有下表中的疾病状态和检测结果(例如,对应于逻辑模型的估计风险)。右边第一个数字是患者数量真正疾病的状态“正常的”,第二个数字是患者数量真正疾病的状态“异常”:
(1)绝对正常:33/3
(2)可能正常:6/2
(3)可疑:6/2
(4)可能异常:11/11
(5)绝对异常:2/33
因此,共有58位“正常”患者和“ 51”位异常患者。我们看到,当预测变量为1时,“绝对正常”,该患者通常是正常的(36位患者中的33位为真),当预测变量为5时,“绝对异常”,该患者通常是不正常的(对于33位患者,则为真。 35位患者),因此预测变量有意义。但是,我们该如何判断得分为2、3或4的患者呢?我们为判断患者是异常还是正常而设置的临界值,以确定所得测试的敏感性和特异性。
敏感性和特异性
我们可以计算出不同临界值的估计灵敏度和特异性。(从现在开始,我将只写“敏感性”和“特异性”,让值的估计性质隐含。)
如果我们选择截止值以便将所有患者分类为异常,则无论他们的测试结果如何(即,我们选择截止值1+),我们将获得51/51 = 1的灵敏度。特异性将为0 / 58 =0。听起来不太好。
好的,让我们选择一个不太严格的临界值。我们仅将检查结果为2或更高的患者分类为异常患者。然后,我们错过了3名异常患者,敏感性为48/51 = 0.94。但是我们的特异性大大提高,为33/58 = 0.57。
我们现在可以继续进行此操作,选择各种截止值(3、4、5,> 5)。(在最后一种情况下,即使他们的最高考试分数为5 ,我们也不会将其分类为异常患者。)
ROC曲线
如果我们针对所有可能的临界值执行此操作,然后将灵敏度相对于1减去特异性作图,则会得到ROC曲线。我们可以使用以下R代码:
# Data
norm = rep(1:5, times=c(33,6,6,11,2))
abnorm = rep(1:5, times=c(3,2,2,11,33))
testres = c(abnorm,norm)
truestat = c(rep(1,length(abnorm)), rep(0,length(norm)))
# Summary table (Table I in the paper)
( tab=as.matrix(table(truestat, testres)) )
输出为:
testres
truestat 1 2 3 4 5
0 33 6 6 11 2
1 3 2 2 11 33
我们可以计算各种统计数据:
( tot=colSums(tab) ) # Number of patients w/ each test result
( truepos=unname(rev(cumsum(rev(tab[2,])))) ) # Number of true positives
( falsepos=unname(rev(cumsum(rev(tab[1,])))) ) # Number of false positives
( totpos=sum(tab[2,]) ) # The total number of positives (one number)
( totneg=sum(tab[1,]) ) # The total number of negatives (one number)
(sens=truepos/totpos) # Sensitivity (fraction true positives)
(omspec=falsepos/totneg) # 1 − specificity (false positives)
sens=c(sens,0); omspec=c(omspec,0) # Numbers when we classify all as normal
并使用它可以绘制(估计的)ROC曲线:
plot(omspec, sens, type="b", xlim=c(0,1), ylim=c(0,1), lwd=2,
xlab="1 − specificity", ylab="Sensitivity") # perhaps with xaxs="i"
grid()
abline(0,1, col="red", lty=2)
手动计算AUC
我们可以使用梯形面积的公式很容易地计算ROC曲线下的面积:
height = (sens[-1]+sens[-length(sens)])/2
width = -diff(omspec) # = diff(rev(omspec))
sum(height*width)
结果是0.8931711。
一致措施
AUC也可以看作是一种一致性度量。如果我们将所有可能的一对患者正常,而另一对异常的患者进行配对,则我们可以计算出具有最高(最“看起来异常”)测试结果的异常患者的频率(如果他们具有相同的值,认为这是“半场胜利”):
o = outer(abnorm, norm, "-")
mean((o>0) + .5*(o==0))
答案还是0.8931711,即ROC曲线下的面积。情况总是如此。
图形化的视图
正如Harrell在他的回答中指出的那样,这也具有图形化的解释。让我们在图上测试得分(风险评估)Ÿ轴和真正的疾病状态的X轴(这里有一些抖动,以示重叠点):
plot(jitter(truestat,.2), jitter(testres,.8), las=1,
xlab="True disease status", ylab="Test score")
现在让我们在左边的每个点(“正常”患者)和右边的每个点(“异常”患者)之间画一条线。具有正斜率的线的比例(即一致对的比例)是一致性指数(平线算作“ 50%一致性”)。
由于联系的数量(相等的风险分数),因此很难直观地看到此示例的实际线条,但是由于有些抖动和透明性,我们可以获得合理的图:
d = cbind(x_norm=0, x_abnorm=1, expand.grid(y_norm=norm, y_abnorm=abnorm))
library(ggplot2)
ggplot(d, aes(x=x_norm, xend=x_abnorm, y=y_norm, yend=y_abnorm)) +
geom_segment(colour="#ff000006",
position=position_jitter(width=0, height=.1)) +
xlab("True disease status") + ylab("Test\nscore") +
theme_light() + theme(axis.title.y=element_text(angle=0))
我们看到大多数直线向上倾斜,因此一致性指数会很高。我们还可以从每种观察对类型中看到对索引的贡献。大部分来自风险评分为1的正常患者,与风险评分为5的异常患者(1-5对),但很多也来自1-4对和4-5对。根据坡度定义很容易计算出实际的一致性指数:
d = transform(d, slope=(y_norm-y_abnorm)/(x_norm-x_abnorm))
mean((d$slope > 0) + .5*(d$slope==0))
答案还是0.8931711,即AUC。
Wilcoxon–Mann–Whitney检验
一致性测度与Wilcoxon-Mann-Whitney检验之间存在密切联系。实际上,后者测试一致性的概率(即,随机的正常-异常对中的异常患者将具有最“看起来异常”的测试结果)是否精确地为0.5。它的检验统计量只是估计的一致性概率的简单转换:
> ( wi = wilcox.test(abnorm,norm) )
Wilcoxon rank sum test with continuity correction
data: abnorm and norm
W = 2642, p-value = 1.944e-13
alternative hypothesis: true location shift is not equal to 0
测试统计量(W = 2642
)计算一致对的数量。如果将其除以可能的对数,则会得到一个熟悉的数:
w = wi$statistic
w/(length(abnorm)*length(norm))
是的,它是0.8931711,ROC曲线下的面积。
计算AUC的简便方法(以R表示)
但是,让我们自己过上轻松的生活。有多种软件包可以自动为我们计算AUC。
Epi包
该Epi
软件包创建了一个不错的ROC曲线,其中嵌入了各种统计信息(包括AUC):
library(Epi)
ROC(testres, truestat) # also try adding plot="sp"
pROC软件包
我也喜欢这个pROC
软件包,因为它可以平滑ROC估算值(并基于平滑的ROC来计算AUC估算值):
(红线是原始的ROC,黑线是平滑的ROC。另请注意默认的1:1宽高比。使用此设置很有意义,因为灵敏度和特异性都在0-1范围内。)
平滑后的 ROC 估计的AUC 为0.9107,与未平滑的 ROC 的估计AUC 相似,但比后者略大(如果您查看该图,您会很容易看出为什么它更大)。(尽管我们实际上只有很少的可能的不同测试结果值来计算平滑的AUC)。
rms软件包
Harrell的rms
软件包可以使用该rcorr.cens()
函数计算各种相关的一致性统计信息。将C Index
在其输出是AUC:
> library(rms)
> rcorr.cens(testres,truestat)[1]
C Index
0.8931711
caTools软件包
最后,我们有了caTools
软件包及其colAUC()
功能。与其他软件包相比,它具有一些优势(主要是速度和使用多维数据的能力–请参阅参考资料?colAUC
),有时可能会有所帮助。但是,当然,它给出的答案与我们一遍又一遍地计算出的结果相同:
library(caTools)
colAUC(testres, truestat, plotROC=TRUE)
[,1]
0 vs. 1 0.8931711
最后的话
许多人似乎认为AUC告诉我们测试的“好”程度。有人认为AUC是测试正确分类患者的概率。这是不是。正如你可以从上面的例子和计算看到,AUC告诉我们一些有关家庭的测试,一个测试为每个可能截止。
而且,AUC是根据在实践中永远不会使用的临界值来计算的。我们为什么要关心“无意义”的临界值的敏感性和特异性?尽管如此,这还是AUC(部分)基于的基础。(当然,如果AUC 非常接近1,几乎所有可能的测试都将具有很大的歧视性,我们都会感到非常高兴。)
AUC的“随机正常-异常”对解释很好(并且可以扩展到生存模型,例如,我们可以看看生存率最高的(相对)危险最早的人)。但是人们永远不会在实践中使用它。在一种罕见的情况下,人们知道一个人有一个健康的人和一个患病的人,不知道哪个人是病的人,必须决定对他们进行治疗。(在任何情况下,决定都是容易的;对待估计风险最高的人。)
因此,我认为研究实际的ROC曲线比仅查看AUC汇总度量更为有用。而且,如果您将ROC与误报和误报的成本(估算值)一起使用,以及所研究课程的基本费率,您将可以找到所需的费用。
另请注意,AUC仅测量辨别力,而不测量校准值。也就是说,它根据风险评分来衡量您是否可以区分两个人(一个病人和一个健康人)。为此,它仅查看相对风险值(如果可以,请参阅排名,请参阅Wilcoxon–Mann–Whitney测试解释),而不是您应该关注的绝对风险值。例如,如果您将每种风险均分根据您的逻辑模型估算2,您将获得完全相同的AUC(和ROC)。
在评估风险模型时,校准也非常重要。为了对此进行检查,您将查看所有风险评分约为0.7(例如0.7)的患者,并查看其中大约70%是否实际生病。对每个可能的风险评分执行此操作(可能使用某种平滑/局部回归)。绘制结果图,您将获得图形化的校准度量。
如果同时具有良好校准和良好辨别力的模型,那么您将开始拥有良好模型。:)