ML ML Learning Lab
08 / 14
第 8 步 · 准确率会骗人

模型评估与验证Model Evaluation & Validation

准确率够了吗?ROC、PR、学习曲线 — 系统性地回答"模型到底好不好"

12 分钟
阅读 + 实操
1 个
交互演示
中高级
难度

模型评估 · 交互演示

损失 BCE--
训练准确率--
准确率 Acc--
AUC--
步数0
学习率 0.1
速度 33步/秒
决策阈值 0.50

为什么学这步?

训练出模型只是开始——更关键的问题是"它到底好不好"。准确率看似直观,却会在不平衡数据上撒谎:99% 都是负类时,全猜负也有 99% 准确率。真实场景里,医疗诊断怕漏诊(召回率要高),垃圾邮件过滤怕误杀(精确率要高),欺诈检测正类极稀少——单一数字回答不了这些侧重点不同的问题。这一步从"会训练"升级到"会评估",是模型走向工业落地的必备技能。

📌 发生了什么

  • ROC 曲线扫阈值画 FPR-TPR 权衡,AUC 概括成一个数(0.5 瞎猜,1.0 完美)。
  • PR 曲线正类稀少时比 ROC 更诚实,关注"报出来的正类有几分真"。
  • 学习曲线回答"数据够不够"——缝隙大是过拟合,两线都高是欠拟合。

⚠️ 常见陷阱

  • 准确率陷阱:不平衡数据下"全猜多数类"就能拿到高准确率,它衡量整体对不对,不是每类好不好。
  • Precision 和 Recall 不能两全:调低阈值抓得全但冤枉多,调高阈值抓得准但漏得多,F1 是折中。
  • 用训练集算指标?自欺欺人。必须用没见过的测试集才能反映泛化能力。

本章小结

  • 准确率会骗人:不平衡数据下需配合 precision / recall / F1 多角度衡量。
  • 混淆矩阵把 TP/FP/FN/TN 摊开,是所有二分类指标的源头。
  • ROC/PR 曲线扫阈值画权衡,学习曲线回答数据够不够。

① ROC 曲线:阈值扫出来的"权衡线"

模型输出的不是"是/否",而是一个概率。把决策阈值从 1 慢慢降到 0,每取一个阈值,就得到一对数字:横轴 FPR(负类里被冤枉成正类的比例,"错杀率"),纵轴 TPR(正类里被成功找出的比例,就是召回率,"抓获率")。把这些点连起来就是 ROC 曲线。曲线越贴近左上角,说明模型越能"抓得全又不错杀"。AUC(曲线下面积)把它概括成一个数:0.5 等于瞎猜,1.0 是完美。

② PR 曲线:不平衡数据下更诚实的尺子

横轴是召回率(正类找回了多少),纵轴是精确率(你报的正类里有多少是真的)。ROC 里的 FPR 分母是庞大的负类,负类一多,错杀几百个 FPR 也纹丝不动;而精确率的分母是"你报出来的正类",每冤枉一个负类都直接拉低它。经验法则:正负均衡看 ROC,正类稀少看 PR

③ 学习曲线:数据够不够,一看便知

做法是:只用 10 个训练样本训一个模型、再用 15 个、20 个……分别记录训练误差和测试误差。数据少时,模型能把几个样本背下来,训练误差(红)很低,但测试误差(蓝)很高——这就是过拟合的样子。两条线最终汇合的高度是模型的极限(欠拟合程度),中间的缝隙是过拟合程度。缝隙大 → 加数据有用;两线都高 → 该换更强的模型了。

📐 精确率、召回率与 F1

二分类混淆矩阵的四个基数(TP/FP/TN/FN)衍生出精确率、召回率和 F1。

F1 分数是精确率与召回率的调和平均,惩罚两者失衡:

更一般地,Fβ 加权调和平均可偏向召回率(β>1)或精确率(β<1):

多分类扩展:宏平均(每类独立计算后取均值)vs 微平均(全局 TP/FP/FN 汇总):

🎛 交叉验证方法对比

不同的评估方法在偏差与方差之间取舍。数据少时用 K 折,数据多时用留出法。

方法 表现 结果
留出法 (70/30) 训练数据少,评估方差大 高方差
5 折交叉验证 偏差与方差均衡,业界默认 推荐
10 折交叉验证 训练数据更多,但计算量翻倍 更精确
留一法 (LOOCV) 偏差最低但方差最高,计算极慢 仅小数据集

💡 Kohavi (1995) 实验表明:10 折交叉验证在多数场景下最优,既稳定又高效。

💻 混淆矩阵 + F1 计算

从预测结果构建混淆矩阵并计算精确率、召回率、F1(Python):

# 构建混淆矩阵
def confusion_matrix(y_true, y_pred):
    tp = fp = fn = tn = 0
    for i in range(len(y_true)):
        if y_pred[i] == 1 and y_true[i] == 1: tp += 1
        elif y_pred[i] == 1 and y_true[i] == 0: fp += 1
        elif y_pred[i] == 0 and y_true[i] == 1: fn += 1
        else: tn += 1
    return tp, fp, fn, tn

# 计算精确率、召回率、F1
def metrics(cm):
    tp, fp, fn, tn = cm
    precision = tp / (tp + fp)
    recall = tp / (tp + fn)
    f1 = 2 * precision * recall / (precision + recall)
    return precision, recall, f1

# K 折交叉验证
def k_fold_split(n, k):
    idx = list(range(n))
    # 打乱后均分 k 份,轮流取一份做验证集
    return idx  # 省略打乱逻辑

📚 参考文献与延伸阅读

  • Kohavi, R. (1995). A Study of Cross-Validation and Bootstrap for Accuracy Estimation and Model Selection. IJCAI — 交叉验证方法对比的经典实验
  • scikit-learn: Model Evaluation — 精确率、召回率、F1 的工业实现
  • Powers, D. M. W. (2011). Evaluation: From Precision, Recall and F-Measure to ROC. — 各类评估指标的统一框架
  • Wikipedia: Confusion matrix — 混淆矩阵的完整定义与扩展

📝 课后练习

检验你的理解——答对为止