我佛了,我今天才搞懂ROC和AUC

ROC: 接收者操作特征曲线(receiver operating characteristic curve),是反映敏感性和特异性连续变量的综合指标,roc曲线上每个点反映着对同一信号刺激的感受性。

“上边儿那个说tm什么玩意儿啊…”,我也是这样想的,先跳过这个概念,强制告诉自己当前情况下,ROC曲线就是 TP率和FP率连成的曲线

AUC (Area Under Curve) 被定义为ROC曲线下的面积

我先给一个手算的Python代码,中间也有调库的
也不算完全手算的,阈值thresholds 是调库获得的
如果你真想完全搞懂到底怎么算的,建议直接单步debug

roc_curve 用于计算ROC曲线的每个点的坐标,以及对应的阈值
roc_auc_score 用于计算AUC,也就是ROC曲线下的面积

import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve
from sklearn.metrics import roc_auc_score

# 固定随机数种子,以使得每次都一样
np.random.seed(1107)

# 编一些数据实例
y_true = np.random.randint(2, size=(100,), dtype="bool")
y_score = np.random.random(size=(100,))

# 按照概率小大排序
order = y_score.argsort()
y_true  = y_true[order]
y_score = y_score[order]


fpr, tpr, thresholds = roc_curve(y_true, y_score)
roc_auc = roc_auc_score(y_true, y_score)
print(roc_auc)


# 我自己算一遍
# 随着阈值改变,有多少真的正例被找出来了
tpr_list = []
for th in thresholds:
    curr_true = (y_score >= th) & y_true
    fenzi  = curr_true.sum()
    fenmu  = y_true.sum()
    tpr_list.append( fenzi / fenmu )
tpr_array = np.array(tpr_list)
tpr_bool = (tpr == tpr_array).all()
print("[tpr]正确: ", tpr_bool)


# 随着阈值改变,假阳性率的变化
fpr_list = []
for th in thresholds:
    curr_false = (y_score >= th) & ~y_true # 将被当做正例的负例拿出来
    fenzi  = curr_false.sum()
    fenmu  = (~y_true).sum()
    fpr_list.append( fenzi / fenmu )
fpr_array = np.array(fpr_list)
fpr_bool = (fpr == fpr_array).all()
print("[fpr]正确: ", fpr_bool)


y_delta = np.diff(tpr)
x_delta = (1 - fpr)[:-1]
auc = (y_delta * x_delta).sum()
print("[AUC]计算正确: ", abs(auc-roc_auc) < 10e-6)


# ROC 曲线, 注意横坐标是 fpr
plt.scatter(fpr, tpr, c="red", s=2)
plt.plot(fpr, tpr)
plt.show()

请添加图片描述
ROC曲线横轴是FP率,纵轴的TP率,写程序绘制ROC曲线时要注意fpr, tpr的顺序是这样,别反了

plt.plot(fpr, tpr)

当年看ROC曲线时,我死活搞不懂,TP率和FP率怎么会变? 那个玩意儿你的模型算出来之后,不是已经定死了么???

假如问题是二分类,要么 T r u e True True,要么 F a l s e False False,然而实际上大部分模型的输出都是是 T r u e True True的概率 P T r u e P_{True} PTrue P F a l s e = 1 − P T r u e P_{False}=1-P_{True} PFalse=1PTrue,除了SVM,SVM只能知道他是正例还是负例,无法知道模型返回的置信度

然而,有一个参数——阈值 v a l val val,来判断一个实例到底是 T r u e True True 还是 F a l s e False False. 所以我们只要让 v a l val val取遍 [ 0 , 1 ] [0, 1] [0,1]的每一个数值,将对应的 ( F P 率 , T P 率 ) (FP率, TP率) (FP,TP) 记录下来,并标到图上,即可获得ROC曲线

然而,实际上无需取遍 [ 0 , 1 ] [0, 1] [0,1]中每一个值,我们只需要取上图中直角处的点就是那个红点,因为相邻红点之间,要么FP率不变,要么TP率不变,也就是两个相邻红点之间,一定是直线
这样的话,可以简化计算了

我们可以调库,查看变量thresholds打印出来是啥:

>>> thresholds
[1.95765094 0.95765094 0.94528669 0.93034073 0.92842689 0.92657479
 0.92291242 0.88343102 0.8810227  0.87744016 0.866908   0.85125653
 0.83371683 0.83208944 0.83117887 0.82556135 0.80705162 0.78068904
 0.77402651 0.73445252 0.720276   0.69508259 0.67662352 0.66001852
 0.63959376 0.62050148 0.61896561 0.59506313 0.57218685 0.54372382
 0.52248361 0.47770536 0.47321275 0.45847792 0.39694008 0.39243611
 0.38743406 0.38383452 0.37590903 0.35305426 0.34275677 0.33935575
 0.31265543 0.28883676 0.25477464 0.24504649 0.2295074  0.22739724
 0.22488244 0.21834767 0.20485498 0.16979291 0.16073303 0.11951154
 0.10385017 0.07318998 0.06647717 0.06036329 0.04527814 0.01842294
 0.01553236]

这些数字是不是有些眼熟呢,来看看这个:

>>> y_score[::-1]
[0.95765094 0.95399522 0.9471417  0.94528669 0.93034073 0.92842689
 0.92657479 0.92522284 0.92291242 0.91543346 0.91397315 0.90965487
 0.90470366 0.88343102 0.8810227  0.87744016 0.866908   0.85821269
 0.85665705 0.85125653 0.83371683 0.83300306 0.83208944 0.83117887
 0.82556135 0.82274304 0.81484892 0.80705162 0.78378691 0.78068904
 0.77402651 0.76804603 0.73851392 0.73445252 0.720276   0.70781191
 0.69508259 0.69000823 0.67662352 0.66001852 0.65615672 0.64420724
 0.63959376 0.62050148 0.61896561 0.59506313 0.57218685 0.55803978
 0.54372382 0.52248361 0.49487794 0.49375354 0.47770536 0.47321275
 0.45847792 0.40366396 0.40161891 0.39694008 0.39243611 0.38743406
 0.38383452 0.37590903 0.36949194 0.3685802  0.36168261 0.35305426
 0.34275677 0.33935575 0.31265543 0.28883676 0.28117519 0.2734256
 0.26876038 0.25477464 0.24504649 0.2295074  0.22739724 0.22542905
 0.22488244 0.21834767 0.20485498 0.17463156 0.17237376 0.16979291
 0.16073303 0.1575529  0.1450476  0.11951154 0.10385017 0.07318998
 0.06647717 0.06605309 0.06036329 0.047198   0.04527814 0.04075525
 0.02959499 0.02274728 0.01842294 0.01553236]

thresholds 中有两个要说的点:

  • thresholds 中的大部分数字来自 y_score ,因为有些 thresholds 即使取了 y_score 中的某个值,也不会使ROC曲线产生直角,也就是说:若 y_score 某个值当做阈值,无法使ROC曲线产生直角,那他也不会被加入到 thresholds 变量中,可以说 :thresholds 变量是经过简化版的 y_score 变量

  • 除了 thresholds[0] 这个数,其余数字都是 y_score 中的数,我也不太清楚 thresholds[0]=1.95765094 这个数字哪里来的,但是他大于1,会使得FP率和TP率都为0

另外,再补充一下,我的AUC是这样计算的:
一横条面积一横条面积不断的加起来的
在这里插入图片描述
顺便说下这两句代码:

>>> fpr, tpr, thresholds = roc_curve(y_true, y_score)
>>> roc_auc = roc_auc_score(y_true, y_score)

>>> y_true
[ True False False False False  True  True False False  True False  True
 False False False  True False False False  True False  True  True False
  True False  True  True  True  True False  True False  True False False
 False False  True False  True False  True  True  True False  True False
 False False  True False False  True False  True False  True  True  True
 False  True  True False False  True False False False  True False False
  True  True  True False  True False False  True False False False  True
 False  True False False False False False  True  True False  True False
  True  True  True  True]
  
>>> y_score
[0.01553236 0.01842294 0.02274728 0.02959499 0.04075525 0.04527814
 0.047198   0.06036329 0.06605309 0.06647717 0.07318998 0.10385017
 0.11951154 0.1450476  0.1575529  0.16073303 0.16979291 0.17237376
 0.17463156 0.20485498 0.21834767 0.22488244 0.22542905 0.22739724
 0.2295074  0.24504649 0.25477464 0.26876038 0.2734256  0.28117519
 0.28883676 0.31265543 0.33935575 0.34275677 0.35305426 0.36168261
 0.3685802  0.36949194 0.37590903 0.38383452 0.38743406 0.39243611
 0.39694008 0.40161891 0.40366396 0.45847792 0.47321275 0.47770536
 0.49375354 0.49487794 0.52248361 0.54372382 0.55803978 0.57218685
 0.59506313 0.61896561 0.62050148 0.63959376 0.64420724 0.65615672
 0.66001852 0.67662352 0.69000823 0.69508259 0.70781191 0.720276
 0.73445252 0.73851392 0.76804603 0.77402651 0.78068904 0.78378691
 0.80705162 0.81484892 0.82274304 0.82556135 0.83117887 0.83208944
 0.83300306 0.83371683 0.85125653 0.85665705 0.85821269 0.866908
 0.87744016 0.8810227  0.88343102 0.90470366 0.90965487 0.91397315
 0.91543346 0.92291242 0.92522284 0.92657479 0.92842689 0.93034073
 0.94528669 0.9471417  0.95399522 0.95765094]

y_truey_score 的shape都是 (n,),(二分类是这样的,多类的暂时不知道…)

y_true 是每个类别
y_score 是类别为 True 的概率

还不懂的话,可以参考这俩篇,我的氵文大多是方便我自己记录和理解,请海涵:

https://blog.csdn.net/u014264373/article/details/80487766
https://www.deeplearn.me/1522.html

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值