核心要点

  • AUC 等价于「随机取一个正样本和一个负样本,正样本得分更高的概率」(Mann-Whitney U 统计量)

  • 排名公式:AUC = (Σ rank(正样本) − P·(P+1)/2) / (P·N),P、N 为正负样本数

  • 同分(tie)要用平均排名(rankdata average),否则结果偏差

  • 另一实现是阈值扫描算 ROC 曲线再用梯形积分,两法结果应一致,可互相验证

标准回答

AUC 是 ROC 曲线下面积,概率含义是「正样本得分高于负样本的概率」。直接对得分排序,用 Mann-Whitney 公式即可 O(N log N) 算出,无需扫描所有阈值。关键是处理同分:得分相同的样本要赋予平均排名,否则正负样本得分相等的情形会被错误计入。下面给出排名法实现,并附阈值扫描法做交叉验证

python
import numpy as np

def auc_rank(y_true, y_score):
    """基于排名的 AUC(Mann-Whitney U)。y_true: 0/1 标签;y_score: 预测分。"""
    y_true = np.asarray(y_true)
    y_score = np.asarray(y_score, dtype=float)
    P = int((y_true == 1).sum())
    N = int((y_true == 0).sum())
    if P == 0 or N == 0:
        return float('nan')                 # 单一类别无法定义 AUC
    # 平均排名处理同分:先按分数排序,对 tie 取平均名次
    order = np.argsort(y_score, kind='mergesort')
    ranks = np.empty(len(y_score), dtype=float)
    sorted_scores = y_score[order]
    i = 0
    while i < len(sorted_scores):
        j = i
        while j + 1 < len(sorted_scores) and sorted_scores[j + 1] == sorted_scores[i]:
            j += 1
        avg_rank = (i + j) / 2 + 1           # 名次从 1 开始
        ranks[order[i:j + 1]] = avg_rank
        i = j + 1
    sum_pos_rank = ranks[y_true == 1].sum()
    return (sum_pos_rank - P * (P + 1) / 2) / (P * N)

def auc_threshold(y_true, y_score):
    """阈值扫描 + 梯形积分,用于交叉验证。"""
    y_true = np.asarray(y_true)
    order = np.argsort(-np.asarray(y_score))   # 分数从高到低
    yt = y_true[order]
    P, Nn = yt.sum(), (1 - yt).sum()
    tps = np.cumsum(yt); fps = np.cumsum(1 - yt)
    tpr = np.concatenate([[0], tps / P]); fpr = np.concatenate([[0], fps / Nn])
    # 梯形积分求 ROC 曲线下面积(不依赖 np.trapz,兼容 NumPy 2.x)
    return float(np.sum((fpr[1:] - fpr[:-1]) * (tpr[1:] + tpr[:-1]) / 2))

if __name__ == '__main__':
    rng = np.random.default_rng(0)
    y = np.array([0, 0, 1, 1, 1, 0, 1, 0])
    s = np.array([0.1, 0.4, 0.35, 0.8, 0.8, 0.2, 0.6, 0.4])
    print('rank AUC   =', round(auc_rank(y, s), 4))
    print('thresh AUC =', round(auc_threshold(y, s), 4))   # 两者一致

常见误区

⚠️ 常见踩坑

忽略同分处理,对 tie 用普通排序而非平均排名,会让 AUC 偏高或偏低;以及当只有单一类别(全正或全负)时 AUC 无定义,应返回 NaN 而非报错。阈值法里也别忘了在 ROC 曲线起点补 (0,0)。

追问

追问 1复杂度是多少?为什么 AUC 对不平衡更稳健?

排名法瓶颈在排序,O(N log N),远快于朴素枚举所有正负样本对的 O(P·N)。AUC 只看正负样本相对排序、与正负比例无关,因此在类别不平衡时比准确率更稳健;但极端不平衡且关注少数类时,PR-AUC 往往更有区分力。

追问 2AUC 高就一定是好模型吗?

不一定。AUC 衡量的是排序能力,不反映概率校准(预测概率是否准)和具体阈值下的精确率/召回率。若业务需要可靠概率或固定阈值表现,还要看校准曲线、PR 曲线和实际工作点指标。

延伸学习

与本题相关的知识库文章、术语、工具与行业资讯。