• 计算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/MN

    从上面的分析过程,不难看出该方法的计算复杂度为 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 - \frac{M(M+1)}{2}}{M * N} AUC=MNiposClassranki2M(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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    某一次运行的结果为:

    sklearn AUC:  0.5292467948717948
    quick_auc is:  0.5292467948717948
    slow_auc is:  0.5292467948717948
    
    • 1
    • 2
    • 3

    可以看出,sklearn中auc,以及我们用上面第二,第三种方法计算得到的auc值,都是完全一致的。

  • 相关阅读:
    盘点世界杯有趣小知识!带你感受体育赛事数据可视化的快乐!
    五款功能强大的国产软件,常常被误认为是外国人开发的
    【考研】时间复杂度与空间复杂度习题练习(含真题)
    Linux vim 文本编辑 操作文本 三种模式
    【图像增强】基于DEHAZENET和HWD的水下去散射图像增强附matlab代码
    分库分表一:ShardingSphere介绍和入门实战
    远场Far-Field beamforming与近场Near-Field beamforming有何关系
    基于springboot+vue的新闻推荐系统
    mybatis拦截器 多租户隔离 及 数据权限隔离 动态可扩展
    DHorse系列文章之操作手册
  • 原文地址:https://blog.csdn.net/bitcarmanlee/article/details/127683716