3. ROC 曲线与 AUC:从绘制原理到多分类扩展

ROC 曲线(Receiver Operating Characteristic Curve)与 AUC(Area Under the Curve)是二分类模型评估中最具鲁棒性的工具之一。它们不依赖固定的分类阈值,能够全面反映模型在不同决策边界下的区分能力。本节从绘制原理出发,逐步深入到 AUC 的统计意义与多分类扩展。

3.1 ROC 曲线绘制原理

ROC 曲线的核心思想是:通过遍历所有可能的分类阈值,计算每个阈值下的 真正例率(TPR) 与 假正例率(FPR),并以 FPR 为横轴、TPR 为纵轴绘制曲线。

指标 公式 含义
TPR(召回率) TP / (TP + FN) 所有真实正例中被正确预测的比例
FPR(假正例率) FP / (FP + TN) 所有真实负例中被错误预测为正例的比例
阈值 θ ∈ [0, 1] 模型输出概率的决策边界

绘制步骤:

  1. 模型对每个样本输出一个概率值(或置信度分数)。
  2. 将所有样本按概率从高到低排序。
  3. 从最高概率开始,依次将每个概率值作为阈值 θ:
    • 概率 ≥ θ 预测为正例,否则为负例。
    • 计算当前阈值下的 TPR 与 FPR。
  4. 将 (FPR, TPR) 点对依次连接,得到 ROC 曲线。
关键理解: 理想模型在左上角(FPR=0, TPR=1)附近;随机模型的 ROC 曲线接近对角线(y=x);曲线越向左上角凸起,模型区分能力越强。
ROC 曲线绘制流程与示例曲线 ROC 曲线绘制流程 ① 模型输出概率分数 ② 按概率降序排列样本 ③ 遍历每个概率作为阈值 θ ④ 计算 TPR 与 FPR ⑤ 连接 (FPR, TPR) 点对 ⑥ 得到 ROC 曲线 示例 ROC 曲线 FPR(假正例率) TPR(真正例率) 随机模型 θ=1.0 θ=0.0 AUC ≈ 0.87

3.2 AUC 的统计意义

AUC(Area Under the ROC Curve)是 ROC 曲线下的面积,取值范围为 [0, 1]。其核心统计意义可以从三个角度理解:

解释角度 含义 数学表达
排序能力 随机抽取一个正例和一个负例,模型将正例排在负例前面的概率 P(Pscore > Nscore)
平均精度 对所有可能阈值下的 TPR 取平均(以 FPR 为权重) ∫01 TPR(FPR) d(FPR)
Wilcoxon 统计量 等价于 Mann-Whitney U 统计量的标准化形式 AUC = U / (np · nn)
实用解读: AUC = 0.5 表示模型无区分能力(等同于随机猜测);AUC = 1.0 表示完美排序;AUC > 0.8 通常认为模型具有较好的区分能力。AUC 对类别不平衡不敏感,因此在正负样本比例悬殊的场景下比准确率更可靠。

3.3 多分类 ROC 扩展

当面对 K 类分类问题时,ROC 曲线需要从二分类扩展到多分类场景。常用的扩展策略有三种:

  • OvR(One-vs-Rest)宏平均: 对每个类别分别计算 ROC 曲线与 AUC,然后取算术平均。每个类别被视为正类,其余所有类别合并为负类。
  • OvR 微平均: 将所有类别的 TP、FP、FN 汇总后,统一计算 TPR 与 FPR,再绘制 ROC 曲线。微平均更关注大类别的表现。
  • OvO(One-vs-One)平均: 对每对类别组合计算 AUC,然后取所有组合的平均值。适用于类别数较少且需要细粒度比较的场景。
方法 计算方式 适用场景 特点
OvR 宏平均 每个类别 AUC 的算术平均 类别均衡、关注小类别 对小类别敏感,受类别不平衡影响较大
OvR 微平均 全局汇总后计算 AUC 类别严重不平衡 受大类别主导,小类别贡献被稀释
OvO 平均 所有类别对的 AUC 平均 类别数少、需细粒度对比 计算复杂度 O(K²),类别多时开销大
多分类 ROC 扩展策略对比 多分类 ROC 扩展策略(K=3 示例) OvR 宏平均 类别 A vs Rest AUC_A = 0.85 类别 B vs Rest AUC_B = 0.78 类别 C vs Rest AUC_C = 0.92 宏平均 AUC = 0.85 OvR 微平均 全局混淆矩阵 TP_总 / FP_总 / FN_总 统一计算 TPR / FPR 微平均 ROC 曲线 微平均 AUC = 0.83 OvO 平均 A vs B: AUC=0.82 A vs C: AUC=0.91 B vs C: AUC=0.79 OvO 平均 AUC = 0.84
实践注意: 在多分类场景中,如果类别数较多(如 K > 10),OvO 方法的计算复杂度会急剧上升(K×(K-1)/2 个二分类模型)。此时优先使用 OvR 宏平均或微平均。另外,多分类 AUC 的解读应结合各类别的样本量,避免被大类别主导的微平均结果误导。

3.4 代码实现:ROC 曲线与 AUC 计算

以下代码使用 scikit-learn 演示二分类与多分类场景下的 ROC 曲线绘制与 AUC 计算:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_curve, auc, roc_auc_score
from sklearn.preprocessing import label_binarize

# ========== 二分类示例 ==========
X, y = make_classification(n_samples=1000, n_features=10, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

model = LogisticRegression()
model.fit(X_train, y_train)
y_prob = model.predict_proba(X_test)[:, 1]

fpr, tpr, thresholds = roc_curve(y_test, y_prob)
roc_auc = auc(fpr, tpr)

print(f"二分类 AUC: {roc_auc:.4f}")

# ========== 多分类示例(OvR 宏平均) ==========
X_multi, y_multi = make_classification(n_samples=1000, n_features=10, n_classes=3, n_informative=5, random_state=42)
X_train_m, X_test_m, y_train_m, y_test_m = train_test_split(X_multi, y_multi, test_size=0.3, random_state=42)

model_multi = LogisticRegression(multi_class='ovr')
model_multi.fit(X_train_m, y_train_m)
y_prob_multi = model_multi.predict_proba(X_test_m)

# 将标签二值化
y_test_bin = label_binarize(y_test_m, classes=[0, 1, 2])
n_classes = y_test_bin.shape[1]

# 计算每个类别的 ROC 与 AUC
fpr_dict = {}
tpr_dict = {}
roc_auc_dict = {}

for i in range(n_classes):
    fpr_dict[i], tpr_dict[i], _ = roc_curve(y_test_bin[:, i], y_prob_multi[:, i])
    roc_auc_dict[i] = auc(fpr_dict[i], tpr_dict[i])

# 宏平均 AUC
macro_auc = np.mean(list(roc_auc_dict.values()))
print(f"多分类 OvR 宏平均 AUC: {macro_auc:.4f}")
print(f"各类别 AUC: {roc_auc_dict}")
关键参数说明:
  • roc_curve(y_true, y_score):返回 fpr、tpr、thresholds 三个数组。
  • auc(x, y):使用梯形法则计算曲线下面积。
  • roc_auc_score(y_true, y_score, multi_class='ovr'):直接计算多分类 AUC,支持 'ovr' 与 'ovo' 参数。
  • 多分类时务必使用 label_binarize 将标签转换为 one-hot 格式,或直接使用 roc_auc_score 的 multi_class 参数。