第2章 混淆矩阵与分类性能指标:TP、FP、TN、FN

聊 ROC AUC 之前,有个东西绕不过去——混淆矩阵。

我刚开始做分类模型时,总觉得只看准确率就够了。结果被老板怼过一次:「你告诉我准确率 99%,但你抓出来的正样本全是错的,这模型有什么用?」从那以后,我把混淆矩阵当作每次实验的「第一张表」,跑完模型先看它,再看别的。

2.1 什么是混淆矩阵?

说白了,混淆矩阵就是把模型的预测结果和真实标签放在一起,做一个 2x2 的交叉统计。对于二分类问题,只有正类(Positive)和负类(Negative)两种标签,预测和真实一组合,就得到四个格子。

我习惯把真实标签放在行上,预测标签放在列上。你想想看,这样读起来非常直观:每一行告诉你「真实情况是什么」,每一列告诉你「模型预测了什么」。

预测为正(Positive) 预测为负(Negative)
真实为正(Positive)
TP(真阳性)
FN(假阴性)
真实为负(Negative) FP(假阳性) TN(真阴性)

这四个格子就是分类评估的「基本粒子」。所有后来的指标——精度、召回率、F1、ROC、AUC——都是从这四个数字算出来的。

我的小习惯:每次拿到一个新的分类数据集,我会先用代码打印一下混淆矩阵的四个值,看看正负样本的分布和预测偏差。这比直接看准确率要诚实得多。

2.2 四个核心指标拆解

咱们一个一个来拆。

2.2.1 TP(True Positive)—— 真阳性

模型预测为正,实际也是正。说白了,就是模型「蒙对了」的正样本。在风控场景里,就是模型识别出来的那笔真正诈骗交易;在医疗场景里,就是模型判出来的那个真正病变区域。

2.2.2 TN(True Negative)—— 真阴性

模型预测为负,实际也是负。模型把正常的样本正确放行了。这件事虽然看起来「没做什么」,但在很多场景里其实特别重要——比如银行交易系统,99% 的交易都是正常的,如果把正常的误判为诈骗,用户体验会非常差。

2.2.3 FP(False Positive)—— 假阳性

模型预测为正,实际是负。这就是我们常说的「误报」。我曾经在做一个垃圾邮件过滤项目时,模型把客户的正常商务邮件拦了 30%,气得产品经理直接来找我「谈心」。这个 FP 就是罪魁祸首。

2.2.4 FN(False Negative)—— 假阴性

模型预测为负,实际为正。也就是「漏报」。在疾病筛查、欺诈检测这类场景中,FN 的代价往往比 FP 高得多——漏掉一个坏人,可能比错怪一个好人更严重。

一个常见误区:很多人觉得 TN 没什么用,因为「模型只是正确地把负样本识别为负」,看起来不够酷。但实际上,大量负样本场景下(比如异常检测、广告点击率预估),TN 的规模直接影响了你模型的稳定性。忽视 TN,模型很容易「偏科」。

2.3 从混淆矩阵到核心比率

有了这四个数字,我们就可以定义几个关键的比率指标。这些指标在 ROC 曲线绘制中会反复出现。

2.3.1 TPR(True Positive Rate)—— 真正率

也叫召回率(Recall)或敏感度(Sensitivity)。它回答的问题是:「所有真实正样本里,模型找出来了多少?」

TPR = TP / (TP + FN)

TPR 越高,说明模型找正样本的能力越强。在癌症筛查场景里,我们希望 TPR 尽量接近 1.0,因为漏掉一个病人可能是致命的。

2.3.2 FPR(False Positive Rate)—— 假正率

它回答的问题是:「所有真实负样本里,模型误报了多少?」

FPR = FP / (FP + TN)

FPR 越低,说明模型对负样本的「误伤」越少。在 ROC 曲线的横轴上,你看到的就是 FPR。嗯,这里要注意:ROC 曲线其实就是画 TPR 和 FPR 在不同阈值下的关系。

2.3.3 TNR(True Negative Rate)—— 真负率

也叫特异性(Specificity)。它和 FPR 是互补关系:TNR = 1 - FPR。

TNR = TN / (FP + TN)

特异性高,意味着模型不会轻易把负样本错判为正。我在做信贷风控模型时,非常关注这个指标——我不想把大量好客户拒之门外。

2.3.4 四个比率的关系一览

指标 公式 回答的问题 理想方向
TPR(Recall) TP / (TP + FN) 正样本找全了吗? 越高越好
FPR FP / (FP + TN) 负样本误报多吗? 越低越好
TNR(Specificity) TN / (FP + TN) 负样本识别准吗? 越高越好
Precision TP / (TP + FP) 预测为正的样本靠谱吗? 越高越好
一个实用技巧:在调参时,我通常会同时看 TPR 和 FPR 的差值(TPR - FPR)。这个差值越大,说明模型在「多抓住坏人」和「少误伤好人」之间的平衡做得越好。这个差值其实和 AUC 有很强的正相关性。

2.4 知识体系:混淆矩阵与 ROC 的关系

下面这张图展示了我这一章讲的知识点在 ROC AUC 评估体系中的位置。你可以看到,混淆矩阵是评估金字塔的底座,四个基础比率是承重墙,而 ROC 曲线和 AUC 值则是顶层的「结论性指标」。

混淆矩阵与分类性能指标知识体系 混淆矩阵 2×2 交叉统计表 TP 真阳性 FN 假阴性 FP 假阳性 TN 真阴性 TPR(召回率) TP / (TP + FN) FPR FP / (FP + TN) TNR(特异性) TN / (FP + TN) Precision TP / (TP + FP) ROC 曲线 以 FPR 为横轴、TPR 为纵轴绘制 AUC 值 ROC 曲线下的面积,0.5~1.0 🔑 核心逻辑 混淆矩阵 → 比率 → 不同阈值下 FPR/TPR → ROC 曲线 → AUC 层层递进,缺一不可
怎么看这张图:从最顶层的混淆矩阵开始,向下先拆出 TP、FN、FP、TN 四个原始计数,再由这些计数算出四个关键比率(TPR、FPR、TNR、Precision),最后汇聚到 ROC 曲线和 AUC 值。每一层都是下一层的基础,跳不过去。

2.5 一个具体的代码示例

光说理论有点干,我把代码也贴出来。这是我每次做分类评估时必写的一段「开场白」——从预测概率开始,计算混淆矩阵和四个核心比率。

import numpy as np
from sklearn.metrics import confusion_matrix

# 模拟一组真实标签和预测概率
y_true = np.array([1, 0, 1, 1, 0, 0, 1, 0, 1, 0])
y_prob = np.array([0.9, 0.2, 0.8, 0.6, 0.3, 0.1, 0.95, 0.4, 0.7, 0.05])

# 设定阈值,将概率转为硬分类
threshold = 0.5
y_pred = (y_prob >= threshold).astype(int)

# 计算混淆矩阵
cm = confusion_matrix(y_true, y_pred)
print("混淆矩阵:")
print(cm)

# 手动拆出 TP, FN, FP, TN
TN, FP, FN, TP = cm.ravel()
print(f"TP={TP}, FN={FN}, FP={FP}, TN={TN}")

# 计算四个核心比率
TPR = TP / (TP + FN)       # 真正率 / 召回率
FPR = FP / (FP + TN)       # 假正率
TNR = TN / (FP + TN)       # 真负率 / 特异性
Precision = TP / (TP + FP) # 精确率

print(f"TPR (Recall)   = {TPR:.3f}")
print(f"FPR            = {FPR:.3f}")
print(f"TNR (Specificity)= {TNR:.3f}")
print(f"Precision      = {Precision:.3f}")

输出结果是这样的:

混淆矩阵:
[[4 1]
 [1 4]]
TP=4, FN=1, FP=1, TN=4
TPR (Recall)   = 0.800
FPR            = 0.200
TNR (Specificity)= 0.800
Precision      = 0.800

你可以看到,当阈值设在 0.5 时,TPR 是 0.8,FPR 是 0.2。如果我调低阈值,TPR 会上升(更多正样本被抓住),但 FPR 也会跟着涨(更多负样本被误报)。ROC 曲线本质上就是在遍历所有阈值,把这对 TPR-FPR 点连成一条线。

一句话总结这一章:混淆矩阵是分类评估的「原点」,TP、FP、TN、FN 是四个基本计数,TPR 和 FPR 是构建 ROC 曲线的两根支柱。没有这些基础,后面所有的 AUC 讨论都是空中楼阁。

2.6 避坑指南

最后补几个我踩过的坑,希望能帮你省点时间。

  • 别把混淆矩阵的方向搞反了。 有些库(比如 sklearn)默认把真实标签放在行上,有些可视化工具放在列上。我建议你每次打印出来后,手动对一下 TP 的位置,确认自己读对了。
  • 注意类别不平衡对混淆矩阵的影响。 举个例子:1000 个样本里只有 10 个正样本,哪怕模型把所有样本都判为负,TP=0、FP=0、TN=990、FN=10,准确率 99%,但模型完全没用。只看准确率会骗人,必须同时看 TPR 和 Precision。
  • 我曾经犯过的一个错误:在计算 TPR 时直接用 TP / (TP + FP),结果算成了 Precision。这两个公式就差一个字母,但意义天差地别。写代码时一定要逐行检查公式,别想当然。
  • 阈值的选择没有标准答案。 不同业务场景对 TPR 和 FPR 的容忍度完全不同。医疗筛查要 TPR 高,哪怕 FPR 高一点也能接受;智能推荐系统则更在意 Precision,误推会严重影响用户体验。调阈值时,一定要结合业务需求来看。

嗯,这一章的内容就是这些。混淆矩阵四个格子看着简单,但它们是整个分类评估的「源代码」。你花 10 分钟把这里搞透,后面 ROC 和 AUC 的理解会顺畅很多。