理解ROC和AUC
分类器各种各样,如何评价这些分类器的性能呢?(这里只考虑二元分类器,分类器的输出为概率值)
方法一:概率定义法
从正样本中随机选取元素记为x,从负样本中随机选取元素记为y,x的置信度大于y的概率
计算方法可以描述为
s=0
for x in 正例:
s+=1/正例总数×置信度小于x的负例所占比例
return s
概率是用来定义问题的利器,如基尼系数。
方法二:正样本排名法
对全部样本按照置信度从高到低进行排序,排名依次记做1,2,3......全部正例的排名之和记为R,R越小表明分类器越准。
方法三:复杂定义法
我提出一种评判指标:点评测法。
给定一个阈值,就可以将分类器的概率值确定化为0、1值。现在只考虑你认为值为1的样本,这些样本占“实际假”样本的比例越小越好,这些样本占“实际为真”的样本的比例越大越好,于是可以得到二元组(这些样本占“实际假”的比例,这些样本占“实际真”的比例)。把这个二元组画在平面直角坐标系中,得到一个点,这个点离(0,1)越近越好!
上面说的是给定了一个阈值,大多数时候,阈值是不好确定的,那就采用“动态阈值”,让阈值从0到1变化就会得到一个点序列,也就是一条曲线。这条曲线就是传说中的ROC。
ROC是一种折线,它是一种评价二值分类器的性能指标
AUC是求折线下面的面积,折线不一定是ROC折线
00:我说0,实际也为0
01:我说0,实际为1
10:我说1,实际为0
11:我说1,实际为1
那么,x坐标可以表示为10/(00+10),y坐标可以表示为11/(01+11)
也就是说,x坐标可以表示为10/x0,y坐标表示为11/x1
也就是说,只看“我说1”的那一部分,该部分在全部“实际0”的部分所占比例为x轴,该部分在“实际1”部分所占比例为y轴。
描述起来多么复杂!但是上面三种方法得到的结果是一模一样的,虽然定义上差很多,但最终说的是一回事!
AUC的直观认识
- AUC对于置信度不敏感,它只关注名次而不关注具体置信度
- 从AUC角度看,好的分类器就是一个好的排序器。分类器在某种程度上就是排序器。
- AUC对于样本正负样本不均衡的现象完全不敏感,从方法一定义上可以看出来。
import sklearn.metrics as metrics
import numpy as np
def roc(y_true, y_mine):
a = [(y_mine[i], y_true[i]) for i in range(len(y_true))]
a = sorted(a, key=lambda x: -x[0])
thresh = sorted(list(set([0, 1] + [i[0] for i in a])), key=lambda x: -x)
cnt = [np.count_nonzero(y_true == 0), np.count_nonzero(y_true == 1), 0, 0]
x = []
y = []
j = 0
for i in thresh:
while j < len(a) and a[j][0] >= i:
if a[j][1]:
cnt[0b11] += 1
cnt[0b01] -= 1
else:
cnt[0b10] += 1
cnt[0b00] -= 1
j += 1
x.append(cnt[0b10] / (cnt[0b00] + cnt[0b10]))
y.append(cnt[0b11] / (cnt[0b11] + cnt[0b01]))
return x, y, thresh
def auc(x, y):
a = sorted([(x[i], y[i]) for i in range(len(x))], key=lambda x: x[0])
area = 0
for i in range(1, len(a)):
area += (a[i - 1][1] + a[i][1]) * (a[i][0] - a[i - 1][0]) / 2
return area
def auc2(y_mine, y_true):
"""
auc的物理意义在于:随机正样本比随机负样本得分高的概率
基于这种直观的思路可以更快速的计算auc
:param y_mine:
:param y_true:
:return:
"""
a = sorted([(y_mine[i], y_true[i]) for i in range(len(y_mine))], key=lambda x: -x[0])
s = 0
true_count = len([1 for i in y_true if i])
false_count = len(y_true) - true_count
total_false = false_count
for i in a:
if i[1]:
s += 1 / true_count * false_count / total_false
else:
false_count -= 1
return s
y_mine = np.random.rand(10)
y_true = np.random.randint(0, 2, 10)
x, y, t = roc(y_true, y_mine)
print(auc(x, y))
print(metrics.auc(x, y))
print(auc2(y_mine, y_true))
其实,auc还可以推导一下得到更简单一点的公式:
def auc2(y_mine, y_true):
"""
auc的物理意义在于:随机正样本比随机负样本得分高的概率
基于这种直观的思路可以更快速的计算auc
本函数只适用于计算得分各不相同的样本,如果存在并列情况,此函数结果错误
:param y_mine:
:param y_true:
:return:
"""
a = sorted(zip(y_mine, y_true), key=lambda x: -x[0])
T = np.count_nonzero(y_true)
F = len(y_true) - T
R = sum(i + 1 for i in range(len(a)) if a[i][1] == 1)
return 1 + (T + 1) / (2 * F) - R / (T * F)
知乎上大神的答案,很高级。
从AUC到真实类别(label)?
最开始思考这个问题是做一个网上的比赛,二分类问题,每次提交一组预测系统会计算出一个AUC值,因为这个比赛只有5000样本,并且系统显示的AUC值有小数点后面7、8位,所以我想是否可以通过可能通过AUC值计算出样本的真实label来。也许并没有实际价值,但是问题本身是很有趣的,像是在破解密码。
一个naive但是可行但是效率很低的办法, 就是每次生成一组预测值,里面只有一个样本预测为1,其余都是0,然后提交预测计算AUC,然后根据这个AUC来判断此样本的label,但是这样效率太低了,5000个样本,需要5000次提交。
思考了很久,最后发现可以通过AUC的另一个计算公式入手。也就是第一部分说的U statistic。
3.1 根据一个AUC值计算样本中0,1的数目
根据AUC与U statistic的联系,我们可以用下面的代码计算AUC:
auc=(sum(rank(c(p(label==1),p(label==0)))[1:n1])-n1*(n1+1)/2)/n0/n1
上面label表示样本的真实类别,p表示预测为1的概率,rank是R的内置函数,n0表示真实数据中0的数目,n1表示1的数目,n0+n1=n表示数据所有样本数目,根据这个简单的一行代码,我们可以不用任何包来计算AUC。
上面公式很有趣,n0,n1还有label都是固定的,p不同导致auc不一致,观察sum里面,可以发现这个sum本质是什么?就是计算pred里面对应的真实label为1的那些预测值的rank的和。
继续使用第一部分的例子,5个样本的预测值的rank:
rank(c(0.5,0.6,0.55,0.4,0.7))[1] 2 4 3 1 5
其中真实为1的样本(1,2,5)的对应rank是2,4,5,这三个rank值的和2+4+5=11,n0=2,n1=3,于是根据上面的AUC公式:(11-3*(3+1)/2)/2/3=5/6=0.83333,这个结果与我们在第一部分用AUC定义算的值完全一样。
所以说,真正影响auc的,就是预测值里面对本来是1的样本的预测的rank的和。
要破解真实label,第一部要做的是找到样本里面0和1的数目,也就是n0和n1等于多少。这个问题不复杂。要知道相同预测值的rank也一致,就是说如果所有样本的预测只取0或者1,那对应的rank只有两个unique数值。
再观察AUC公式里面的sum:
sum(rank(c(pred(label==1),pred(label==0)))[1:n1])
这个sum是n1个数值的和,这n1个数值,当我们的pred只有两个不同取值的时候,仅包括两个unique的数值。继续用上面例子,一共有5个样本,我们生成第一组预测p如下:
> p=c(1,1,1,0,0)> rank(p)[1] 4.0 4.0 4.0 1.5 1.5
可见p的rank只有两个不同取值,1.5和4,这是因为预测概率p也只有两个不同取值。
然后我们还知道sum是n1个数的sum,我们不知道的是这n1个数,里面有几个1.5,几个4,假设其中有k1个1.5,k2个4,可以列出一个方程:
k1+k2=n1
k1*1.5+k2*4=sum(rank(c(p(label==1),p(label==0)))[1:n1])=auc*n0*n1+n1*(1+n1)/2
所以最终得到下面的方程组:
k1+k2=n1
k1*1.5+k2*4=0.833333*n0*n1+n1*(1+n1)/2
n0+n1=5
其中k1,k2和n1未知,两个方程,3个未知数,属于不定方程组,但是要知道k1,k2,和n1都是整数,并且有取值范围,要借出来很简单,写一个for 循环,1秒中就可以找到一组满足3个方程多k1,k2以及n1。
如果我们变更p,比如p=c(rep(1,m),rep(0,5-m)),通过一样的算法,可以计算出来前m个样本中1的数量。
通过这个算法,我可以算出来这个贷款预测比赛测试数据中有509个1和4491个0。
做到这里,差点就放弃了,但是后来突然又有了灵感,找到了下面的算法:
3.2 根据AUC破解样本的真实label
这里就省略思考过程了, 直接来破解算法:
对于一组总数为n的测试样本,我们先来计算
m=floor(log(n,base=2))+1
这个m表示我们通过两次auc计算可以计算出至少多少个样本的真实label,比如n=5000,那么m=13
也就是说通过我们两次提交,可以最少得到13个样本的label。这13个样本是可以自己随便指定的,比如我们对前13个样本感兴趣,那么具体做法如下:
fix1=2^c(0:12)fix2=c(fix1[-1],fix1[1])unfixed=setdiff(1:5000,fix1)p1=c(fix1,unfixed)#第1组预测p2=c(fix2,unfixed)#第2组预测
使用上面的两组预测p1和p2分别计算AUC,得到auc1和auc2,根据上面给出的auc算法:
sum(rank(c(p1(label==1),p1(label==0)))[1:n1])-n1*(1+n1)/2=auc1*n0*n1sum(rank(c(p2(label==1),p2(label==0)))[1:n1])-n1*(1+n1)/2=auc2*n0*n1
两个公式相减:
sum(rank(c(p1(label==1),p1(label==0)))[1:n1])-sum(rank(c(p2(label==1),p2(label==0)))[1:n1])-n1*(1+n1)/2=(auc1-auc2)*n0*n1
得到的这个等式里,我们已经通过上面的方法找到了n0和n1,auc1和auc2是已知,所以等式右面值可以算出,那么等式左面呢,因为我们两个预测结果p1和p2只有前三个点的预测之不一样,其余点的预测值一样,rank也一样,那么等式左面的两个sum的差,其实只由前13个样本的真实label决定,具体来说:
sum1-sum2=y1*(fix1[1]-fix2[1])+y2*(fix1[2]-fix2[2])+...+y13*(fix1[13]-fix2[13])=y1*(-1)+y2*(-2)+...+y12*(-2048)+y13*(4095)
上面的方程里面yi代表样本i的真实label,有且只有唯一解,以为这个方程本质上就是10进制数用2进制表达。所以通过两次auc计算,我们可以找到13个点的真实标签。比如对上面提到的贷款预测比赛,选定前13个label,auc1=0.50220853,auc2= 0.5017588,然后就可以算出来前13个test样本只有第三个样本是0,其余都是1。
但是13并不是上限,我有一些更好的结果,比较复杂,在这就不展开说了。
参考资料
https://www.zhihu.com/question/39840928
理解ROC和AUC的更多相关文章
- ROC和AUC理解
一. ROC曲线概念 二分类问题在机器学习中是一个很常见的问题,经常会用到.ROC (Receiver Operating Characteristic) 曲线和 AUC (Area Under th ...
- 机器学习性能指标之ROC和AUC理解与曲线绘制
一. ROC曲线 1.roc曲线:接收者操作特征(receiveroperating characteristic),roc曲线上每个点反映着对同一信号刺激的感受性. 横轴:负正类率(false po ...
- ROC和AUC介绍以及如何计算AUC ---好!!!!
from:https://www.douban.com/note/284051363/?type=like 原帖发表在我的博客:http://alexkong.net/2013/06/introduc ...
- 【转】ROC和AUC介绍以及如何计算AUC
转自:https://www.douban.com/note/284051363/ ROC(Receiver Operating Characteristic)曲线和AUC常被用来评价一个二值分类器( ...
- 评估分类器性能的度量,像混淆矩阵、ROC、AUC等
评估分类器性能的度量,像混淆矩阵.ROC.AUC等 内容概要¶ 模型评估的目的及一般评估流程 分类准确率的用处及其限制 混淆矩阵(confusion matrix)是如何表示一个分类器的性能 混淆矩阵 ...
- ROC与AUC学习
全文转自:https://www.cnblogs.com/gatherstars/p/6084696.html#commentform 这篇真的讲的清楚明白!要多复习!加深记忆! 1.概述 AUC(A ...
- 机器学习-Confusion Matrix混淆矩阵、ROC、AUC
本文整理了关于机器学习分类问题的评价指标——Confusion Matrix.ROC.AUC的概念以及理解. 混淆矩阵 在机器学习领域中,混淆矩阵(confusion matrix)是一种评价分类模型 ...
- 【分类问题中模型的性能度量(二)】超强整理,超详细解析,一文彻底搞懂ROC、AUC
文章目录 1.背景 2.ROC曲线 2.1 ROC名称溯源(选看) 2.2 ROC曲线的绘制 3.AUC(Area Under ROC Curve) 3.1 AUC来历 3.2 AUC几何意义 3.3 ...
- ROC and AUC
目录 概 TPR, FPR ROC and AUC 代码 ROC-wiki 概 AUC常常在文章中作为评价一个分类器优劣的指标, 却总是忘记其原由, 索性记上一笔. TPR, FPR 首先理解TP, ...
随机推荐
- select点击option获取文本输入框的焦点事件
HTML文件: <select id="secOrderNum" style="margin-bottom:10px;width:90px;" data- ...
- [JQuery] jQuery选择器ID、CLASS、标签获取对象值、属性、设置css样式
reference : http://www.suyunyou.com/aid1657.html jQuery是继prototype之后又一个优秀的Javascrīpt框架.它是轻量级的js库(压缩后 ...
- Glusterfs初试
Gluster的模式及介绍在此不表,这里只记录安装及配置过程. 1.整体环境 server1 : gfs1.cluster.com server2 : gfs2.cluster.com Client: ...
- go语言基础之copy的使用
1.copy的使用 示例: package main //必须有个main包 import "fmt" func main() { srcSlice := []int{1, 2} ...
- (转)U3D DrawCall优化手记
自:http://www.cnblogs.com/ybgame/p/3588795.html 在最近,使用U3D开发的游戏核心部分功能即将完成,中间由于各种历史原因,导致项目存在比较大的问题,这些问题 ...
- PREEMPT_RT的未来
因为开发资金的问题,Thomas Gleixner宣布他已经不想干了. 商业公司往往用了PREEMPT_RT的功能去不愿意去回报社区,那就自己弄吧. http://lwn.net/Articles/6 ...
- socketio server推送
假设面试官问你:要把server端的数据时时显示在浏览器上怎么实现?我想有非常多人会回答使用Ajax技术定时去訪问一个资源,没错,使用Ajax的确能实现.但面试官要的绝对不是这个答案. 由于使用Aja ...
- 控制系统音量,自己定义MPVolumeView
近期有一个需求,就是控制系统的音量,我们都知道原理在mediaPlayer.framework框架下,有方法 <span style="font-size:18px;"> ...
- 在Foreda8中整合Apche httpd2.4.6和Tomcat7.0.42(使用tomcat-connectors-1.2.37)
本地Apche httpd2.4.6(http://pan.baidu.com/share/link?shareid=4003375081&uk=34256769)和Tomcat7.0.42是 ...
- 【已解决】Python脚本运行出现语法错误:IndentationError: unindent does not match any outer indentation level
转自:http://www.crifan.com/python_syntax_error_indentationerror/comment-page-1/ [问题] 一个python脚本,本来都运行好 ...