如何手动计算曲线下面积(AUC)或c统计量


78

我对手工计算二进制逻辑回归模型的曲线下面积(AUC)或c统计量感兴趣。

例如,在验证数据集中,我具有因变量的真实值(保留(1 =保留; 0 =不保留)),以及通过使用以下模型进行回归分析而生成的每个观察值的预测保留状态:使用训练集构建(范围从0到1)。

我最初的想法是确定模型分类的“正确”数目,然后将“正确”观察数除以总观察数即可计算出c统计量。通过“正确”,如果观察的真实保留状态= 1且预测的保留状态> 0.5,则为“正确”分类。另外,如果观察值的真实保留状态= 0并且预测的保留状态<0.5,则这也是“正确”的分类。我假设当预测值= 0.5时会出现“领带”,但在我的验证数据集中不会出现这种现象。另一方面,“不正确”分类将是观察的真实保留状态= 1且预测的保留状态<0。5或结果的真实保留状态= 0且预测的保留状态> 0.5。我知道TP,FP,FN,TN,但不知道在给定此信息的情况下如何计算c统计量。

Answers:


115

我会推荐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曲线

手动计算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"

Epi包中的ROC曲线

pROC软件包

我也喜欢这个pROC软件包,因为它可以平滑ROC估算值(并基于平滑的ROC来计算AUC估算值):

pROC套件中的ROC曲线(未平滑和平滑)

(红线是原始的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

caTools软件包中的ROC曲线

最后的话

许多人似乎认为AUC告诉我们测试的“好”程度。有人认为AUC是测试正确分类患者的概率。这是不是。正如你可以从上面的例子和计算看到,AUC告诉我们一些有关家庭的测试,一个测试为每个可能截止。

而且,AUC是根据在实践中永远不会使用的临界值来计算的。我们为什么要关心“无意义”的临界值的敏感性和特异性?尽管如此,这还是AUC(部分)基于的基础。(当然,如果AUC 非常接近1,几乎所有可能的测试都将具有很大的歧视性,我们都会感到非常高兴。)

AUC的“随机正常-异常”对解释很好(并且可以扩展到生存模型,例如,我们可以看看生存率最高的(相对)危险最早的人)。但是人们永远不会在实践中使用它。在一种罕见的情况下,人们知道一个人有一个健康的人和一个患病的人,不知道哪个人是病的人,必须决定对他们进行治疗。(在任何情况下,决定都是容易的;对待估计风险最高的人。)

因此,我认为研究实际的ROC曲线比仅查看AUC汇总度量更为有用。而且,如果您将ROC与误报和误报的成本(估算值)一起使用,以及所研究课程的基本费率,您将可以找到所需的费用。

另请注意,AUC仅测量辨别力,而不测量校准值。也就是说,它根据风险评分来衡量您是否可以区分两个人(一个病人和一个健康人)。为此,它仅查看相对风险值(如果可以,请参阅排名,请参阅Wilcoxon–Mann–Whitney测试解释),而不是您应该关注的绝对风险值。例如,如果您将每种风险均分根据您的逻辑模型估算2,您将获得完全相同的AUC(和ROC)。

在评估风险模型时,校准也非常重要。为了对此进行检查,您将查看所有风险评分约为0.7(例如0.7)的患者,并查看其中大约70%是否实际生病。对每个可能的风险评分执行此操作(可能使用某种平滑/局部回归)。绘制结果图,您将获得图形化的校准度量。

如果同时具有良好校准和良好辨别力的模型,那么您将开始拥有良好模型。:)


8
谢谢@Karl Ove Hufthammer,这是我收到的最彻底的答复。我特别感谢您的“最终用语”部分。优秀作品!再次感谢!
马特·赖兴巴赫

非常感谢您提供详细的答案。我正在使用Epi :: ROC()v2.2.6确信AUC为1.62(不是心理研究)的数据集,但是根据ROC,我相信上述代码结果会在0.56中产生更多影响英寸
BurninLeo

32

看看这个问题:了解ROC曲线

这是建立ROC曲线的方法(根据该问题):

绘制ROC曲线

给定由您的排名分类器处理的数据集

  • 对分数递减的测试示例进行排名
  • 开始于(0,0)
  • 对于每个示例(以降序排列) x
    • 如果为正,则将向上移动1 / POSx1/pos
    • 如果为负数,向右移动1 /负数x1/neg

其中和分别是正例和负例的分数。NEGposneg

您可以使用以下想法使用以下算法来手动计算AUC ROC:

auc = 0.0
height = 0.0

for each training example x_i, y_i
  if y_i = 1.0:
    height = height + tpr
  else 
    auc = auc + height * fpr

return auc

这张精美的gif动画图片应更清楚地说明此过程

建立曲线


1
感谢@Alexey Grigorev,这是一个很棒的视觉效果,将来可能会有用!+1
马特·赖兴巴赫2015年

1
请解释一下“正例和负例的分数”,您是说两轴的最小单位值吗?
艾伦·卢恩

1
@Allan Ruin:pos这里指的是阳性数据的数量。假设您有20个数据点,其中11个点是1。因此,绘制图表时,我们有一个11x9矩形(高x宽)。阿列克谢·格里戈列夫(Alexey Grigorev)确实可以扩展,但是只要您愿意就可以扩展。现在,只需在图表的每一步移动1。
Catbuilts

5

卡尔的帖子有很多很好的信息。但是在过去的20年中,我还没有看到ROC曲线能够改变任何人的思维方向的例子。在我拙见中,ROC曲线的唯一值是它的面积恰好等于一个非常有用的一致性概率。ROC曲线本身会诱使读者使用临界值,这是不好的统计实践。

如作为手动远计算 -index,使曲线与上的轴和连续预测器或预测的概率的轴。如果将的每个点与每个点连接,则具有正斜率的线的比例为一致性概率。ÿ = 0 1 X ÿ = 1个Ŷ Ŷ = 0 ÿ = 1cY=0,1xY=1yY=0Y=1

在此设置中,分母为任何度量都是不正确的准确性评分规则,应避免使用。这包括正确分类的比例,敏感性和特异性。n

对于R Hmiscrcorr.cens功能,请打印整个结果以查看更多信息,尤其是标准错误。


谢谢@弗兰克·哈雷尔,谢谢您的见解。我只是将c统计量用作一致性概率,因为我不喜欢使用临界值。再次感谢!
马特·赖兴巴赫

4

这是自然计算AUC的另一种方法,只需使用梯形法则即可得出ROC曲线下的面积。

AUC等于随机抽样的阳性观察结果的预测概率(为阳性)大于随机抽样的阴性观察结果的概率。您可以通过正向和负向观测的所有成对组合使用它来在任何编程语言中轻松地计算AUC。如果样本量太大,也可以随机抽样观察值。如果要使用笔和纸来计算AUC,除非您有非常少的样本/很多时间,否则这可能不是最佳方法。例如在R中:

n <- 100L

x1 <- rnorm(n, 2.0, 0.5)
x2 <- rnorm(n, -1.0, 2)
y <- rbinom(n, 1L, plogis(-0.4 + 0.5 * x1 + 0.1 * x2))

mod <- glm(y ~ x1 + x2, "binomial")

probs <- predict(mod, type = "response")

combinations <- expand.grid(positiveProbs = probs[y == 1L], 
        negativeProbs = probs[y == 0L])

mean(combinations$positiveProbs > combinations$negativeProbs)
[1] 0.628723

我们可以使用以下pROC软件包进行验证:

library(pROC)
auc(y, probs)
Area under the curve: 0.6287

使用随机抽样:

mean(sample(probs[y == 1L], 100000L, TRUE) > sample(probs[y == 0L], 100000L, TRUE))
[1] 0.62896

1
  1. 您具有观察的真正价值。
  2. 计算后验概率,然后根据该概率对观察值进行排名。
  3. 假设的截止概率和观察值:Ñ 真行列萨姆- 0.5 P Ñ P Ñ + 1 PN
    Sum of true ranks0.5PN(PN+1)PN(NPN)

1
@ user73455 ... 1)是的,我对观察有真正的价值。2)后验概率与每个观测值的预测概率同义吗?3)了解;但是,什么是“真实等级总和”?如何计算此值?也许有一个例子可以帮助您更彻底地解释这个答案?谢谢!
马特·赖兴巴赫
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.