计算AUC的方法以及代码实现
Posted bitcarmanlee
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算AUC的方法以及代码实现相关的知识,希望对你有一定的参考价值。
1.传统的AUC计算方法
传统的AUC计算方法,就是计算ROC曲线下围成的面积。具体的详情可以参考下文
入门选手都能理解的ROC曲线与AUC值
在比较早期的Machine Learning相关资料中,最常见介绍的计算AUC方法就是这种。由于我们实际样本是有限的,得到的AUC曲线必然是一个阶梯状。因此实际计算时候,可以将score先排序。假设score越大,样本为正例的概率越大,我们一边扫描就可以得到我们想要的AUC。但是这样做有个缺点,就是当多个测试样本的score相等的时候,我们调整一下阈值,得到的不是曲线一个阶梯往上或者往右的延展,而是斜着向上形成一个梯形。此 时,我们就需要计算这个梯形的面积。因此,用这种方法计算得到AUC是比较麻烦的。
2.Wilcoxon-Mann-Whitney test
这是一个two-sample test的非参数检验版本,对标的参数检验版本是t-test。
具体可以参考
Mann–Whitney U test
不要问我原理,说实话我也不是特别懂,没有深入研究过…
重点看结论:
AUC跟Wilcoxon-Mann-Witney Test是等价的。Wilcoxon-Mann-Witney Test就是测试任意给一个正类样本和一个负类样本,正类样本的score有多大的概率大于负类样本的score。有了这个定义,我们就得到了另外一中计 算AUC的办法:得到这个概率。
具体来说,假设样本中有正负样本分别为M,N个,那么样本中一共会有MN个样本对。我们在这MN个样本对中,计算出正样本分数比负样本分数高的样本数假设为C,那么AUC的值为
C
/
M
∗
N
C / M*N
C/M∗N
从上面的分析过程,不难看出该方法的计算复杂度为 O ( n 2 ) O(n^2) O(n2),其中n为样本总数,n = M + N。
3.快速计算方法
上面第二种方法的计算复杂度较高,我们可以稍作改进,得到更为快速的计算方法
按概率从高到矮排个降序, 对于正样本中概率最高的,排序为rank_1, 比它概率小的有M-1个正样本(M为正样本个数), (rank_1 - M) 个负样本。
正样本概率第二高的, 排序为rank_2, 比它概率小的有M-2个正样本,(rank_2 - M + 1) 个 负样本。
以此类推
正样本中概率最小的, 排序为rank_M,比它概率小的有0个正样本,rank_M - 1 个负样本。
总共有MxN个正负样本对(N为负样本个数)。把所有比较中 正样本概率大于负样本概率 的例子都算上, 得到公式(rank_1 - M + rank_2 - M + 1 … + rank_M - 1) / (MxN) 就是正样本概率大于负样本概率的可能性了。 化简后(因为后面是个等差数列)得:
A U C = ∑ i ∈ p o s C l a s s r a n k i − M ( M + 1 ) 2 M ∗ N AUC = \\frac\\sum_i \\in posClass rank_i - \\fracM(M+1)2M * N AUC=M∗N∑i∈posClassranki−2M(M+1)
4.代码实现
前面理论都已经说完,接下来又到了show me the code环节。
直接上code
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Author: WangLei
#date: 2022/11/3
import numpy as np
from sklearn.metrics import roc_auc_score
def gen_score_and_label():
y_scores = np.zeros(100)
y_labels = np.zeros(100)
for i in range(100):
y_scores[i] = np.random.random()
y_labels[i] = np.random.choice([0, 1])
return y_labels, y_scores
def cal_auc_self(y_labels, y_scores):
f = sorted(list(zip(y_scores, y_labels)), key=lambda x: x[0])
rank = [value2 for _, value2 in f]
rankindex = [i+1 for i in range(len(rank)) if rank[i] == 1]
pos_count = np.sum(y_labels == 1)
neg_count = np.sum(y_labels == 0)
quick_auc = (np.sum(rankindex) - pos_count * (pos_count + 1) / 2) / (pos_count * neg_count)
print("quick_auc is: ", quick_auc)
fpos = [v1 for v1, v2 in f if v2 == 1]
fneg = [v1 for v1, v2 in f if v2 == 0]
rightcount = 0
for score_pos in fpos:
for score_neg in fneg:
if score_pos > score_neg:
rightcount += 1
slow_auc = rightcount / (pos_count * neg_count)
print("slow_auc is: ", slow_auc)
def main():
y_labels, y_scores = gen_score_and_label()
print('sklearn AUC: ', roc_auc_score(y_labels, y_scores))
cal_auc_self(y_labels, y_scores)
main()
某一次运行的结果为:
sklearn AUC: 0.5292467948717948
quick_auc is: 0.5292467948717948
slow_auc is: 0.5292467948717948
可以看出,sklearn中auc,以及我们用上面第二,第三种方法计算得到的auc值,都是完全一致的。
以上是关于计算AUC的方法以及代码实现的主要内容,如果未能解决你的问题,请参考以下文章