第2章:混淆矩阵详解——TP、FP、TN、FN 的定义与实战意义

上一章我们聊了 ROC 曲线的整体框架。但在动手画曲线之前,有个基础概念必须得先啃透——混淆矩阵。

说白了,混淆矩阵就是一张表。它能把模型预测的结果和真实标签之间的所有关系,一字排开呈现在你面前。我刚开始做分类任务时,经常搞混 TP、FP 这些缩写。后来发现,只要你理解了这个矩阵,几乎所有的分类评估指标都能从这里推导出来。

2.1 从一次预测开始

假设我们有个二分类问题。比如判断一封邮件是不是垃圾邮件。真实情况有两种:“是垃圾邮件”(正类)或“不是垃圾邮件”(负类)。模型预测也有两种:“预测为垃圾邮件”或“预测为正常邮件”。

把这两种情况交叉组合,就会出现四种结果:

  • TP (True Positive):真实是正类,模型也预测为正类。
  • TN (True Negative):真实是负类,模型也预测为负类。
  • FP (False Positive):真实是负类,但模型预测为正类。
  • FN (False Negative):真实是正类,但模型预测为负类。

注意看,名字里第一个词是“True”或“False”,指的是预测对不对。第二个词是“Positive”或“Negative”,指的是模型预测的结果。我遇到过不少同学把“False Positive”理解成“预测为假正例”,那就全拧了。

核心记忆口诀:第一个词判断对错,第二个词看预测。TP 就是“预测说真,实际也是真”;FP 就是“预测说真,但实际是假”。

2.2 矩阵长什么样

把它画成 2x2 矩阵,看起来更清楚:

预测为正类 预测为负类
真实为正类 TP FN
真实为负类 FP TN

行是真实标签,列是预测结果。读的时候先看行再看列。比如第一行第一列:真实正类、预测正类,那就是 TP。

2.3 实际计算:拿代码说话

说了这么多理论,不如直接跑一段代码。假设我们有 10 个样本的真实标签和预测结果:

y_true = [1, 0, 1, 1, 0, 0, 1, 0, 1, 0]
y_pred = [1, 0, 0, 1, 1, 0, 1, 0, 0, 0]

手动推一下:

  • y_true=1 且 y_pred=1:位置 0、3、6 → 3 个 TP
  • y_true=0 且 y_pred=0:位置 1、5、7、9 → 4 个 TN
  • y_true=0 但 y_pred=1:位置 4 → 1 个 FP
  • y_true=1 但 y_pred=0:位置 2、8 → 2 个 FN

用 sklearn 验证一下:

from sklearn.metrics import confusion_matrix

y_true = [1, 0, 1, 1, 0, 0, 1, 0, 1, 0]
y_pred = [1, 0, 0, 1, 1, 0, 1, 0, 0, 0]

tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel()

print(f"TP: {tp}, TN: {tn}, FP: {fp}, FN: {fn}")

输出结果:

TP: 3, TN: 4, FP: 1, FN: 2

跟我手算的结果完全一致。`ravel()` 是为了把矩阵展平成一维数组,顺序是 TN、FP、FN、TP。这个顺序很多新手会搞错,我建议你每次用之前都打印出来看一眼。

小技巧:sklearn 的 confusion_matrix 返回的是 2x2 矩阵。可以直接通过索引访问:
cm = confusion_matrix(y_true, y_pred)
tn = cm[0, 0]
fp = cm[0, 1]
fn = cm[1, 0]
tp = cm[1, 1]

2.4 为什么这几个数那么重要?

你想想看,几乎所有分类指标都是从这 4 个数算出来的:

  • 准确率 (Accuracy):全部猜对的比例。(TP + TN) / 总数
  • 精确率 (Precision):预测为正类中有多少是真的正类。TP / (TP + FP)
  • 召回率 (Recall):真的正类中有多少被找出来了。TP / (TP + FN)
  • 特异度 (Specificity):真的负类中有多少被正确排除。TN / (TN + FP)

举个例子。做癌症筛查时,FP 意味着“没病被误诊成有病”,病人要承受不必要的心理压力和后续检查。FN 意味着“有病没查出来”,可能会错过最佳治疗期。你说哪个更致命?

我曾在医疗影像项目里遇到过类似情况。当时的模型准确率高达 98%,但 FN 其实有 5 例。放到临床上,这就是 5 个漏诊患者。后来我们调整了分类阈值,哪怕牺牲一点精确率,也要把召回率提上去。这就是 TPR 和 FPR 的博弈。

避坑指南:千万不要只看准确率。数据不平衡时,准确率会骗人。比如 99% 的样本都是负类,模型全猜负类也有 99% 准确率,但 FN 会非常惨。这种情况我遇到过好几次,每次都后悔没早点看混淆矩阵。

2.5 从混淆矩阵到 TPR 和 FPR

铺垫了这么多,终于要聊到跟 ROC 曲线直接相关的两个指标了:

  • 真正率 (TPR) = TP / (TP + FN) = 召回率
  • 假正率 (FPR) = FP / (TN + FP)

ROC 曲线本质上就是不断改变分类阈值,算出一组 (FPR, TPR),然后把这些点连成线。

比如我们将判断垃圾邮件的阈值从 0.5 降到 0.3。预测为正类的样本变多了,TP 和 FP 会同时增加。对应的 TPR 和 FPR 也会变化。把这些变化画出来,就是 ROC 曲线。

下面这张图可以帮你直观理解 TP、FP、TN、FN 在数据空间中的位置关系:

混淆矩阵四格空间 真实标签 正类 负类 预测结果 预测为正类 预测为负类 TP 真实正类 预测正类 (正确命中) FN 真实正类 预测负类 (漏报) FP (误报) TN (正确排除)

2.6 实际业务中的权衡

不同场景对 FP 和 FN 的容忍度完全不同。我整理了一个清单,你可以参考一下:

场景 更讨厌 原因
癌症筛查 FN 漏诊可能延误治疗,后果严重
垃圾邮件过滤 FP 误杀正常邮件会影响用户体验
信用卡欺诈检测 FN 漏掉一笔欺诈交易就可能造成经济损失
内容审核 FP 误删合法内容会引发争议和流失

所以,在评估模型时一定要先明确业务约束。你想最大化召回率还是最大化精确率?这直接决定了你要在 ROC 曲线上选哪个点作为最终决策阈值。

我的个人习惯:会先算混淆矩阵,再算 TPR 和 FPR。算完这两项,才动手绘制 ROC 曲线。顺序别搞反,否则容易遗漏数据分布特征。

混淆矩阵虽然基础,但它是理解 ROC 曲线的第一步。把这 4 个格子里的数字搞清楚,后面的灵敏度、特异度、AUC 这些概念才能接得住。