文章目录
- 前言
- TPR,FPR
- ROC
- AUC
- 实战
- 鸣谢
- average precision (AP)
- 实战
前言
开门见山,想要知道AUC必须知道ROC,想要知道ROC必须知道TPR,FPR,
完。
TPR,FPR
TPR:true positive rate
FPR:false positive rate
EXAMPLE 1: 我们有一个模型算法,它能够根据一系列的属性(比如身高、爱好、衣着、饮食习惯等)来预测一个人的性别是男还是女。
下面是这个模型算法对10个人的是男还是女的预测值和10个人的真实值。其中预测值为0.72表示72%的概率认为是男,28%的概率认为是女。
如果我们设定区分男女的阈值是0.5,即预测值大于0.5的我们认为是男性,小于0.5是女性。
记:男=阳性=正向,女=阴性=负向
那么,6个男人中有[1,3,5,8,9]这5个被查出来了,算法M的查出率TPR=5/6=0.833;4个女性中6号被查错,所以误检率FPR=1/4=0.25;精度(正确率)ACC=(5+3)/10=0.8。
但是注意,如果我们修改阈值等于0.4,那么就会变为6个男人全被检出,从而查出率TPR=1;而女性则被误检2个,故FPR=0.5;此时精度仍然是0.8。
ROC
EXAMPLE 2:
当病人来检查是否有病的时候,他就以概率随机写有病。
结果呢,对于所有真实有病的个人,庸医能正确检查出个人,就是TPR=,同样对于没病的个人,也是误检,从而FPR=。
这个庸医的“随机诊法”总能得到相等的查出率和误检率,如果我们把FPR当做坐标横轴,TPR当做纵轴,那么“随机诊法”对应了(0,0)到(1,1)的那条直线,记。
我们分析一下上面这张图:越靠近左上角的情况查出率越高,查错率越低,(0,1)点是最完美的状态。而越靠近右下角,算法质量越低。
注意图中右下角C点,这里查错率高,查出率低,属于很糟糕的情况;但是如果我们把C点沿红色斜线对称上去成为C’点,那就很好了。——所以,如果你的算法预测结果总是差的要死,那么可以试试看把它颠倒一下,记算法预测是男的,你就说是女的,我们得到一个新的算法,此时就变成了C’点。
回想前面的第一个例子(男女预测),我们知道阈值的改变会严重影响FPR和TPR,那么,如果我们把所有可能的阈值都尝试一遍,再把根据样本集预测结果计算得到的所有(FPR,TPR)点都画在坐标上,就会得到一个曲线:
ROC(Receiver Operating Characteristic curve)接受者操作特征曲线。
在这个图中,注意:
- 横轴竖轴都不是阈值坐标轴,还是(FPR,TPR),这里没有显示的表示出阈值。图上的一个点背后其实就对应着一个阈值。
- 蓝色线更加靠近左上角,比红色线更好。
AUC
ROC曲线的形状不太好量化比较,于是就有了AUC。
AUC,Area under the Curve of ROC,就是ROC曲线下面的面积。如上图,蓝色曲线下面的面积更大,也就是它的AUC更大。
如图,左侧的红色折线覆盖了下面整个方形面积,AUC=1;中间的曲线向左上方凸起,AUC=0.8;右边的是完全随机的结果(庸医的”随机诊法“),占一半面积,AUC=0.5。
AUC面积越大,算法越好。
当我们写好算法之后,可以用测试集来让这个算法进行分类预测,然后我们绘制ROC曲线,观察AUC面积,计算ACC精度,用这些众多指标,综合考虑,来对我们的算法的好坏进行更加全面的评估。
实战
前提,安装了sklearn,如果你的是anaconda安装的话默认是安装了的。
import numpy as np
from sklearn.metrics import roc_auc_score,roc_curve
y = np.array([1, 1, 2, 2])
scores = np.array([0.1, 0.4, 0.35, 0.8])
fpr, tpr, thresholds = roc_curve(y, scores, pos_label=2)
#表示类别2代表阳性,如果你的类别是0,1或者-1,1,那么默认阳性是1,我们这里是1,2,必须指定谁是阳性,否则报错。
print(fpr,tpr,thresholds)
[0. 0. 0.5 0.5 1. ]
[0. 0.5 0.5 1. 1. ]
[1.8 0.8 0.4 0.35 0.1 ]一个threshold对应一个(fpr,tpr),从而可以在坐标轴上绘制这个点
大家可能会有一个疑问,为什么会输出5个阈值,因为选择其他阈值,fpr,tpr也总是上面的5组之一,所以没有必要再选择阈值了。换句话说,如果你的输入y不一样,有可能不是输出5个阈值,看情况的。
将上述 5个点绘制如下:
那么问题来了,5个点无法构成roc曲线啊,怎么办,根本没法计算?很简单,这些点可以相互连接起来成为一个折线,就可以计算啦。
大功告成,我们可以轻松计算AUC的值为1-0.25=0.75,我们验证一下。
roc_auc_score(y, scores)
0.75
average precision (AP)
AP可以类比AUC,也是一个曲线下的面积,只是这个曲线叫做recall-precision曲线,而AUC的那个曲线是FPR-TPR曲线(或者叫做ROC曲线),所以你可以认为几乎一摸一样。
所以,聪明的你可以想到,对于AP,我们只需要知道如何计算recall和precision就可以了,下面介绍之。
和AUC一样,也要区分阳性是谁,在下图这个例子中,我们假设2是阳性,1是阴性。
我们假设阈值是0.5,即预测值大于0.5就认为预测结果是阳性。那么,其预测结果就是[1,1,1,2]。那么:
- precision=1/1,即预测了1个2,而且对了,百发百中。
- recall=1/2,总共有2个2,但是只预测到了1个,从而50%。
官方一点,即:
和ROC一样,我们设置不同的阈值,我们会得到不同的准确率和召回率。从而,我们可以将其画在坐标轴上,然后连成一个曲线,计算其面积。
实战
下面的实战可以类比上面的实战,几乎一样,所以仅仅展示区别。
import numpy as np
from sklearn.metrics import precision_recall_curve
from sklearn.metrics import average_precision_score
y = np.array([1, 1, 2, 2])
scores = np.array([0.1, 0.4, 0.35, 0.8])
precision,recall,thresholds=precision_recall_curve(y,scores,pos_label=2)
print(precision)
print(recall)
print(thresholds)
同样道理,为什么
- 为什么3个阈值,却有4个(recall,precision),最后一个是固定不变的,默认就一定会加上(0,1),含义是阈值如果足够大,那么预测结果中就不会有阳性的,没有预测,那么默认precision=1,由于预测的全是阴性的,所以recall=0。其实吧,我个人觉得,这个是sklearn没有设计好,阈值应该加上1个数变成4个比较好,至于加什么?可以加1个比0.8大的数就行。例如变成[0.35 0.4 0.8,1 ],这样比较好理解。
- 只有3个阈值,因为更换其他的阈值,得到的(recall,precision)还是上面的4个之一。
下面是precision_recall_curve
更加官方的解释。
Returns
precision : array, shape = [n_thresholds + 1]
Precision values such that element i is the precision of
predictions with score >= thresholds[i] and the last element is 1.recall : array, shape = [n_thresholds + 1] Decreasing recall
values such that element i is the recall of predictions with score >=
thresholds[i] and the last element is 0.thresholds : array, shape = [n_thresholds
<=len(np.unique(probas_pred))]
Increasing thresholds on the decision function used to compute precision and recall.
总之,不管怎么样,我们可以将上面的4个点画在图中,就像是下面这样的:
细心的你会发现和前面的ROC曲线并不相同,在ROC曲线中左上角是最好的点,这里恰恰相反,左上角和右下角都是很差的点,反而右上角是最好的点。其中,那个蓝色的线就代表基准,你的模型在蓝色的线上面就越好。
同样的一个问题,上面是4个点,该怎么连线变成precision_recall_curve曲线呢?如下:
也就是:
其中,。
上面这个看不懂没关系,记得上面那个图就行。从而我们可以根据上面公式或者图算出面积AP=0.83,我们验证一下:
average_precision_score(y, scores,pos_label=2)
0.8333333333333333
成功。
完结撒花