200 个正类、800 个负类,扫完所有阈值画出的 ROC 曲线 AUC 是 0.7984,随机猜是 0.5000。 TPR 减 FPR 的最大值 0.483(KS 统计量)出现在阈值 0.5 附近。
上一节的精确率、召回率都依赖阈值。 这一节讲一个不看阈值的工具:把阈值从头扫到尾,把结果画成一条曲线。
一、ROC 怎么画
两个轴:横轴是 FPR(负类里被误判为正的比例),纵轴是 TPR(也就是召回率,正类里被抓到的比例)。 画法:把阈值从高到低扫一遍。阈值极高时一个都不判正,点在 (0, 0);阈值极低时全判正,点在 (1, 1)。 中间每调一次得到一个点,连起来就是曲线。 左上角 (0, 1) 是理想点:一个误报都没有,全都抓到了。曲线越靠近左上角越好。 曲线下的面积就是 AUC。0.5 是瞎猜(对角线),1.0 是完美。
二、实测:AUC 0.7984
Demo 造了 200 个正类(打分均值 1)和 800 个负类(均值 0),标准差都是 1。 两类有重叠,所以不可能是完美分类器。 扫完所有阈值,AUC 算出来是 0.7984。 AUC 的含义很好记:随机抽一个正样本和一个负样本,模型给正样本打分更高的概率。 0.7984 就是「八成的概率能排对」。 表里给了六个阈值的具体值。 可以看到 TPR 和 FPR 一起涨,但 TPR 涨得更快——这就是模型有区分能力的意思。 TPR 减 FPR 的最大值是 0.483,出现在阈值 0.5 附近。 这个差叫 KS 统计量,它对应的阈值常被当成「最佳切点」。
三、AUC 的好处和坑
好处:和阈值无关。换阈值只是在曲线上挪位置,不改面积。 所以它可以用来比较「模型本身的能力」,不用先定阈值。 好处二:不受类别比例影响(严格说是不受先验影响)。 同一个模型在 1:1 和 1:100 的数据上,AUC 差不多。 坑:正因为不受比例影响,类别极不平衡时它会虚高。 FPR 的分母是负类总数,负类有 800 个,误报几十个 FPR 也涨不了多少,曲线看着还是很漂亮。 这时要看 PR 曲线(精确率对召回率)。PR 曲线的基线是正类占比——这里正类只占 20%,基线就是 0.20。 一眼能看出模型到底比瞎猜好多少。 实践中两个都算、两个都报。只看 AUC 会在不平衡数据上自我感觉良好。
四、训练师该怎么用这两个曲线
选模型:AUC 高的通常更好,但要确认两个模型的适用场景一致。 如果两个模型 AUC 差不多,看 PR 曲线——业务关心的是「抓出来的对不对」,那 PR 更贴近。 定阈值:别看曲线,看业务约束。 比如「误报率不超过 5%」,就在 FPR 等于 0.05 的那一列往上找 TPR 最高的点。 汇报:AUC 一个数就够(好解释),但必须补一句「正类占比多少」。不写这个,AUC 的含义会被误解。 排查:如果 AUC 只有 0.5 到 0.6,先别调模型,去看特征是不是漏了关键信息。 0.5 附近的 AUC 通常意味着「模型看到的东西和标签没关系」。
五、动手 Demo:ROC 与 AUC:扫完所有阈值,面积 0.7984
造 200 个正类和 800 个负类的打分(正类均值 1、负类均值 0,标准差都是 1); 按打分从高到低排序,逐步累积真正例和假正例,得到整条 ROC 曲线; 用梯形法算曲线下面积,并列出六个阈值上的 TPR、FPR 和两者之差。
order = np.argsort(-sc)
ysort = y[order]
tp = np.cumsum(ysort)
fp = np.cumsum(1 - ysort)
tpr = np.concatenate([[0.0], tp / float(n_pos)])
fpr = np.concatenate([[0.0], fp / float(n_neg)])
auc = float(np.trapezoid(tpr, fpr))
实跑输出:
--------------------------------------------------------------------
ROC 曲线:把所有阈值扫一遍画成一条线
--------------------------------------------------------------------
样本 正类 200 个、负类 800 个
打分 正类 ~ N(1, 1),负类 ~ N(0, 1)
沿着打分从高到低扫,每个位置算一次「抓到的正类比例」和「误报的负类比例」,画出来就是 ROC 曲线。曲线下的面积就是 AUC。
阈值 TPR(召回) FPR(误报率) TPR 减 FPR
----------------------------------------------
2.0 0.175 0.020 0.155
1.5 0.325 0.059 0.266
1.0 0.550 0.144 0.406
0.5 0.710 0.285 0.425
0.0 0.875 0.480 0.395
-1.0 0.980 0.829 0.151
这条曲线的 AUC 0.7984
随机猜的 AUC 0.5000
完美分类器的 AUC 1.0000
TPR 减 FPR 最大处 0.483(这是 KS 统计量,也是常用阈值)
AUC 的含义是「随机抽一个正样本和一个负样本,正样本打分更高的概率」。所以 0.5 是瞎猜,1.0 是完美。实测 **0.7984**,说明这个模型有明显区分能力,但离完美还远。
AUC 有个好性质:它和阈值无关。换阈值只会在曲线上挪位置,不改面积。所以它可以用来比较「模型本身的能力」,不用先定阈值。
它也有个坑:类别极不平衡时 AUC 会虚高。因为 FPR 的分母是负类总数,负类有 800 个,误报几十个 FPR 也涨不了多少。
这种情况下要看 PR 曲线(精确率对召回率)。PR 曲线的基线是正类占比,这里正类只占 20%,基线就是 0.20,一眼能看出模型到底比瞎猜好多少。
实践中的做法:两个都算,两个都报。只看 AUC 会在不平衡数据上自我感觉良好。
AUC 0.7984。这个数比 0.5 高得多,说明模型有明确区分能力; 但离 1.0 还远,因为两类分布重叠得厉害。 表里阈值 0.5 那行:TPR 0.710、FPR 0.285,差 0.425。阈值 1.0 那行差 0.406。 两者接近,说明 0.5 到 1.0 这个区间切点都不错。 KS 最大值 0.483 落在阈值 0.5 附近。 这个位置是「TPR 领先 FPR 最多」的地方,常被当成最佳切点——但它只考虑排序能力,不考虑业务代价。 正类只占 20%,AUC 0.7984 看着不错。 但如果算 PR 曲线,基线是 0.20,模型在召回 0.7 时精确率只有 0.5 左右——提升空间比 AUC 暗示的小。 这就是「AUC 虚高」的具体表现。
30 秒实验
- 把正类的打分均值从 1 改成 2,看 AUC 涨到多少。
- 把负类数量从 800 改成 200(正负 1:1),看 AUC 变不变——想想为什么。
- 想一想:AUC 0.8 的模型,在正类只占 1% 的数据上,实际能用吗?
常见误区
- 「AUC 高就一定好」——不平衡数据上它虚高,得配合 PR 曲线看。
- 「AUC 可以用来定阈值」——它和阈值无关,定阈值要回到 PR 表或代价分析。
- 「AUC 0.5 是随机,所以 0.55 也差不多」——0.55 确实很弱,但方向是对的。
自测三问(点开对答案)
1. ROC 曲线的两个轴是什么? —— 横轴是 FPR(负类被误判为正的比例),纵轴是 TPR(也就是召回率)。 2. AUC 的直观含义是什么? —— 随机抽一个正样本和一个负样本,模型给正样本打分更高的概率。 3. 为什么不平衡数据上 AUC 会虚高? —— FPR 的分母是负类总数,负类多时误报几十个 FPR 也涨不了多少,曲线看起来仍然漂亮。五个指标讲完了。下一节开始讲优化:怎么用验证集判断模型是不是真的学到了东西。
- ☐ (本节完,下一节 9.2.1 Holdout检验:用训练集训练模型并测试性能)