AUC完全总结:定义、手撕计算代码、优缺点

ROC曲线

二分类混淆矩阵如下:

真实情况label=1 真实情况label=0
预测情况label=1 TP FP
预测情况label=0 FN TN
  • 假阳率(False Positive Rate) FPR=FP/(FP + TN),即在所有真实的负样本中,预测结果为正的比例,越小越好
  • 真阳率(True Positive Rate) TPR=TP/(TP + FN),即在所有真实的正样本中,预测结果为正的比例,越大越好

ROC曲线通过选取很多阈值,来计算FPR、TPR,然后以FPR为横坐标,以TPR为纵坐标画出的曲线就是ROC曲线

AUC的定义

AUC(Area Under ROC Curve),是ROC曲线下的面积。如果ROC面积越大,说明曲线越往左上角靠过去。那么对于任意截断点,(FPR,TPR)坐标点越往左上角(0,1)靠,说明FPR较小趋于0(在所有真实负样本中,基本没有预测为正的样本),TRP较大趋于1(在所有真实正样本中,基本全都是预测为正的样本)。并且上述是对于任意截断点来说的,很明显,那就是分类器对正样本的打分基本要大于负样本的打分。

AUC越大,说明分类器越可能把正样本排在前面,衡量的是一种排序的性能。所以AUC也有另一个常用的的定义:随机从正样本和负样本中各选一个,分类器对于该正样本打分大于该负样本打分的概率

AUC的计算

方法1-概率法

按照上述给出的常用的AUC定义,我们可以很容易得到时间复杂度为O(n^2)的计算方式(n为样本数量):

def cal_auc_1(label, pred):
    numerator = 0    # 分子
    denominator = 0  # 分母
    for i in range(len(label) - 1):
        for j in range(i, len(label)):
            if label[i] != label[j]:
                denominator += 1
                # 统计所有正负样本对中,模型把相对位置排序正确的数量
                r = (label[i] - label[j]) * (pred[i] - pred[j])
                if r > 0:
                    numerator += 1
                elif r == 0:
                    numerator += 0.5
    return numerator / denominator

方法2-概率法优化版

我们可以对方法1进行优化。

假设数据集一共有M个正样本,N个负样本,预测值也就是M+N个。我们将所有样本按照预测值进行从小到大排序,并排序编号由1到M+N

  • 对于正样本概率最大的,假设排序编号为rank1,比它概率小的负样本个数= rank1−M
  • 对于正样本概率第二大的,假设排序编号为rank2,比它概率小的负样本个数=rank2−(M−1)
  • 以此类推......
  • 对于正样本概率最小的,假设排序编号为rankM,比它概率小的负样本个数=rankM−1

那么在所有情况下,正样本打分大于负样本的个数= rank1 +...+ rankM - (1+2+...+M),这样我们可以通过时间复杂度为O(n*logn)的算法进行计算

需要注意的是,对于正负样本概率相等的情况,我们通过双指针法(快慢指针),将概率分子多加的部分去掉

def cal_auc_2(label, pred):
    m = sum(label)
    n = len(label) - m

    numerator = - m * (m + 1) / 2
    denominator = m * n
    
    # 根据预测的概率大小进行升序排序
    rank = [[l, p] for l, p in sorted(zip(label, pred), key=lambda x: x[1])]
    
    # cur代表慢指针,指向最后一个已经计算好的数据
    cur = -1
    cur_pos_num = 0
    for i in range(len(rank)):
        if rank[i][0] == 1:
            numerator += i + 1
            cur_pos_num += 1
        
        if i == len(rank) - 1 or rank[i][1] != rank[i + 1][1]:
            if cur_pos_num > 0:
                numerator -= (i - cur - cur_pos_num) * 0.5
            cur = i
            cur_pos_num = 0

    return numerator / denominator

方法3-面积法

由于我们的测试样本是有限的,我们得到的AUC曲线必然是一个阶梯状的。因此,计算的AUC也就是这些阶梯下面的面积之和。我们先按预测score排序,然后一遍扫描就可以得到我们想要的AUC,时间复杂度为O(n*logn)

def cal_auc_3(label, pred):
    m = sum(label)
    n = len(label) - m
    
    # 根据预测的概率大小进行排序
    rank = [[l, p] for l, p in sorted(zip(label, pred), key=lambda x: x[1], reverse=True)]
    
    tp = fp = pre_tp = pre_fp = auc = 0
    
    for i in range(len(rank)):
        if rank[i][0] == 1:
            tp += 1
        else:
            fp += 1
            
        if i == len(rank) - 1 or rank[i][1] != rank[i + 1][1]:
            # 梯形面积计算公式
            auc += (tp + pre_tp) * (fp - pre_fp) / 2
            pre_tp = tp
            pre_fp = fp
    auc /= m * n
    return auc

AUC优缺点

优点

  • 阈值独立:不同于其他指标比如precision,recall,F1,AUC不依赖于特定的阈值,而是考虑所有可能的阈值,可以全面评估模型的性能
  • 直观解释:AUC的值在0-1之间,AUC 值越大,表示模型区分正负样本的能力越强。AUC值为0.5表示模型没有区分能力,相当于随机猜测

缺点

  • 没有给出模型误差的空间分布信息:AUC只关注正负样本之间的排序,并不关心正样本内部,或者负样本内部的排序
  • 无法区分错误类型:AUC只提供一个整体的性能评估,无法反映召回率、精确率等在实际业务中经常关心的指标
  • 在极端不平衡数据集上的局限性:在极端不平衡的情况下(如正类样本极少),AUC可能无法完全反映模型的性能,其他指标(如PR曲线下的面积,AP)可能更合适

为什在极端不平衡数据上,auc会接近1?

因为正样本非常少,模型只需要正确分类少量正样本即可使TPR快速上升,而FPR由于负样本基数大,即使有一定数量的误分类,增加的幅度也相对较小。这会导致ROC曲线在靠近左上角的位置迅速上升,形成一个接近直角的曲线,进而使 AUC 接近1

所以在极端不平衡数据上,即使auc很高,也不能说明模型的性能很好,此时模型的FP数量可能远远大于TP,精确率会存在问题

你可能感兴趣的:(机器学习笔记,机器学习,深度学习,算法)