图谱连接

草稿

混淆矩阵

对二分类垃圾邮件分类结果计数,不仅看整体正确率,还要区分误报和漏报。

concept beginner machine-learningmetricsclassification

代入问题:评估垃圾邮件过滤器

你有一个模型,每封邮件被标记为 spamnot-spam。 你需要知道的不仅是“有多少封邮件是对的”,还要知道“错在哪里”。

这个固定数据集有 12 封邮件:

垃圾邮件数据集合每封邮件都有真实标签和模型预测。
e1

立即领取奖品

明显的中奖诱饵,被过滤器拦下。

actual: 垃圾邮件(spam)pred: 垃圾邮件(spam)TP: 真正例(true positive)
e2

项目笔记

普通工作邮件,被留在收件箱。

actual: 非垃圾邮件(not-spam)pred: 非垃圾邮件(not-spam)TN: 真负例(true negative)
e3

收据已附上

真实收据被错误标成垃圾邮件。

actual: 非垃圾邮件(not-spam)pred: 垃圾邮件(spam)FP: 假正例(false positive)
e4

账户提醒

伪造提醒漏进了收件箱。

actual: 垃圾邮件(spam)pred: 非垃圾邮件(not-spam)FN: 假负例(false negative)
e5

限时优惠

促销垃圾邮件被正确拦截。

actual: 垃圾邮件(spam)pred: 垃圾邮件(spam)TP: 真正例(true positive)
e6

团队午餐

团队日常邮件被正确保留。

actual: 非垃圾邮件(not-spam)pred: 非垃圾邮件(not-spam)TN: 真负例(true negative)
e7

密码重置

用户请求的重置邮件正常送达。

actual: 非垃圾邮件(not-spam)pred: 非垃圾邮件(not-spam)TN: 真负例(true negative)
e8

紧急转账

诈骗邮件被过滤器漏掉。

actual: 垃圾邮件(spam)pred: 非垃圾邮件(not-spam)FN: 假负例(false negative)
e9

航班变更

有用的出行更新被误报。

actual: 非垃圾邮件(not-spam)pred: 垃圾邮件(spam)FP: 假正例(false positive)
e10

加密币奖励

可疑奖励垃圾邮件被正确拦截。

actual: 垃圾邮件(spam)pred: 垃圾邮件(spam)TP: 真正例(true positive)
e11

发票已批准

业务发票被正确接收。

actual: 非垃圾邮件(not-spam)pred: 非垃圾邮件(not-spam)TN: 真负例(true negative)
e12

验证钱包

钓鱼式钱包邮件被漏判。

actual: 垃圾邮件(spam)pred: 非垃圾邮件(not-spam)FN: 假负例(false negative)

第一个朴素想法

最直接想到的分数是总正确率:

正确 / 总数

对这 12 封邮件是 7 / 12 = 58.3%

但这会把不同错误混在一起:

正确/错误二分总正确率会忽略错误类型。
TP: 真正例(true positive) + 正确

计数:3

e1, e5, e10

TN: 真负例(true negative) + 正确

计数:4

e2, e6, e7, e11

总正确/错误

正确 = TP + TN = 7

错误 = FP + FN = 5

错误为什么不一样痛

e3e4 都是错,但语义完全不同:

  • e3:真实不是垃圾邮件却被拦截(误报),
  • e4:真实是垃圾邮件却放过了(漏报)。
误报与漏报两种错误都算错,却会产生完全不同影响。

e3

收据已附上

真实收据被错误标成垃圾邮件。

真实: 非垃圾邮件(not-spam), 预测: 垃圾邮件(spam) (FP: 假正例(false positive))

e4

账户提醒

伪造提醒漏进了收件箱。

真实: 垃圾邮件(spam), 预测: 非垃圾邮件(not-spam) (FN: 假负例(false negative))

核心发明

把判断拆成两个是/否问题:

  • 真实标签 actual 是不是正类;
  • 预测标签 predicted 是不是正类。

这就得到四个格子。

核心 2×2 分桶两个二元问题定义了四个分桶。

种子示例:e1→TP,e3→FP,e2→TN,e4→FN。

种子示例计数(非完整统计)
真实预测=垃圾邮件预测=非垃圾邮件
真实=垃圾邮件1 (e1)1 (e4)
真实=非垃圾邮件1 (e3)1 (e2)

两类真实标签构成行,两个预测标签构成列。

交互演示

逐步处理 12 条邮件,观察每一步只给一个格子加一。

混淆矩阵追踪

第 1/12 步:将 e1 计入 真正例(true positive)(TP)。

真实: 垃圾邮件; 预测: 垃圾邮件.

e1: 立即领取奖品,真实为“spam”(正类),预测为“spam”(正类),因此属于 真正例(true positive)(TP)。

当前计数

TP=1, FP=0, TN=0, FN=0

总计 = 1

TP 变更:0 → 1。

最终不变量

TP + FP + TN + FN = 12

正确 = TP + TN = 7

错误 = FP + FN = 5

当前计数表
真实 \ 预测正类 1负类 0
真实=正类TP: 1FN: 0
真实=负类FP: 0TN: 0
步骤账本(当前行已标注)
当前步StepId主题真实预测Cell
当前1e1立即领取奖品垃圾邮件垃圾邮件TP: 真正例(true positive)
2e2项目笔记非垃圾邮件非垃圾邮件TN: 真负例(true negative)
3e3收据已附上非垃圾邮件垃圾邮件FP: 假正例(false positive)
4e4账户提醒垃圾邮件非垃圾邮件FN: 假负例(false negative)
5e5限时优惠垃圾邮件垃圾邮件TP: 真正例(true positive)
6e6团队午餐非垃圾邮件非垃圾邮件TN: 真负例(true negative)
7e7密码重置非垃圾邮件非垃圾邮件TN: 真负例(true negative)
8e8紧急转账垃圾邮件非垃圾邮件FN: 假负例(false negative)
9e9航班变更非垃圾邮件垃圾邮件FP: 假正例(false positive)
10e10加密币奖励垃圾邮件垃圾邮件TP: 真正例(true positive)
11e11发票已批准非垃圾邮件非垃圾邮件TN: 真负例(true negative)
12e12验证钱包垃圾邮件非垃圾邮件FN: 假负例(false negative)

切换正类到 not-spam 时(为方便对照)当前步会改到:

TP=0, FP=0, TN=1, FN=0

这个示例是确定性的:同一封邮件始终带来同一步迁移。

正式定义

y 是真实标签,\hat{y} 是模型预测。 在本节点中,正类明确声明为:

1 = spam0 = not spam

以下用行列法定义矩阵(行是实际,列是预测):

y^=1y^=0y=1TPFNy=0FPTN\begin{array}{c|cc} & \hat{y}=1 & \hat{y}=0 \\ \hline y=1 & TP & FN \\ y=0 & FP & TN \end{array}

1 表示“正类”这一约定,而不是“更正确”。

TPFPTNFN 是这四个格子的计数。

矩阵方向行是现实(真实标签),列是模型输出(预测标签)。
本页方向约定
预测为正类预测为负类
真实为正类TPFN
真实为负类FPTN

不变量为:

TP+FP+TN+FN=n.TP + FP + TN + FN = n.

n 是已评估邮件数。

共享的数据给出:

  • TP = 3
  • FP = 2
  • TN = 4
  • FN = 3
  • correct = TP + TN = 7
  • wrong = FP + FN = 5
  • total = 12

实现草图

每条邮件只会进入一个格子并更新一个计数器:

if (actual === positiveLabel && predicted === positiveLabel) {
  tp += 1;
} else if (actual !== positiveLabel && predicted === positiveLabel) {
  fp += 1;
} else if (actual !== positiveLabel && predicted !== positiveLabel) {
  tn += 1;
} else {
  fn += 1;
}
实现分支四个条件分别映射到一个计数器更新。
实现分支
若真实是正类?若预测是正类?更新含义
真实正类预测正类TP++真正例(true positive)
真实负类预测正类FP++假正例(false positive)
真实负类预测负类TN++真负例(true negative)
真实正类预测负类FN++假负例(false negative)

正确性直觉

两个布尔问题是穷尽且互斥的。

对同一个正类定义,每条邮件只属于这四种组合之一:

  • 实际正类且预测正类
  • 实际负类且预测正类
  • 实际负类且预测负类
  • 实际正类且预测负类

因此每条邮件只进入一个格子。处理 9 条后是:

TP = 2,FP = 2,TN = 3,FN = 2,总计 9。

到全部 12 条结束后是:

TP = 3,FP = 2,TN = 4,FN = 3,总计 12。

轨迹不变量每条样本只会进入且仅进入一个分桶。
After e9

TP=2, FP=2, TN=3, FN=2

total = 9

formula: TP + FP + TN + FN = 9

最终

TP=3, FP=2, TN=4, FN=3

总数 = 12

不变量:每条样本恰好映射到一个单元。

可写成前缀不变量:

TP+FP+TN+FN=已处理样本数TP + FP + TN + FN = \text{已处理样本数}

到末尾时,已处理样本数即 12。

复杂度

这类扫描是单次遍历:

time=O(n),extra space=O(1).\text{time} = O(n), \qquad \text{extra space} = O(1).

每封邮件做固定次数比较和一次计数器更新。

常见误解

常见误区命名与方向错误是最常见的误解来源。
正类定义

当前表:正类是 spam(1 表示垃圾邮件)。

正类 = spam
预测=垃圾邮件预测=非垃圾邮件
真实=垃圾邮件3 (TP)3 (FN)
真实=非垃圾邮件2 (FP)4 (TN)
切换正类

若正类改成 not-spam,不同单元格含义发生重分配。

正类 = not-spam
预测=非垃圾邮件预测=垃圾邮件
真实=非垃圾邮件4 (TP)2 (FN)
真实=垃圾邮件3 (FP)3 (TN)

再看一个“换正类”练习,保持真实/预测标签不变,改 positiveLabel = "not-spam"

  • TP = 4
  • FP = 3
  • TN = 3
  • FN = 2

这不改变预测本身,只改变了我们问“正类是什么”的问题。

图谱关联

这会是 precision、recall、f1-score 的基础节点;这些节点目前计划中尚未全部上线。

图谱走向当前后续节点尚未实现,仅用于学习路径提示。
confusion-matrix

已实现

precision

计划后续

recall

计划后续

f1-score

计划后续

静态追踪账本(无 JS 回退)

下面这张账本完全静态,JS 关闭也可查看,并且与交互轨迹一致:

12 条邮件追踪账本
邮件主题真实预测格子TPFPTNFN
1e1立即领取奖品spamspamTP(真正例(true positive))1000
2e2项目笔记not-spamnot-spamTN(真负例(true negative))1010
3e3收据已附上not-spamspamFP(假正例(false positive))1110
4e4账户提醒spamnot-spamFN(假负例(false negative))1111
5e5限时优惠spamspamTP(真正例(true positive))2111
6e6团队午餐not-spamnot-spamTN(真负例(true negative))2121
7e7密码重置not-spamnot-spamTN(真负例(true negative))2131
8e8紧急转账spamnot-spamFN(假负例(false negative))2132
9e9航班变更not-spamspamFP(假正例(false positive))2232
10e10加密币奖励spamspamTP(真正例(true positive))3232
11e11发票已批准not-spamnot-spamTN(真负例(true negative))3242
12e12验证钱包spamnot-spamFN(假负例(false negative))3243

不变量校验:TP + FP + TN + FN = 12。

练习

  1. e9 的格子是什么?
  2. 把正类改成 not-spam 后,e9 落入哪个格子?
  3. 在本页定义里,如果真实为 not-spam 但预测为 spam,对应哪个术语?
  4. 为什么只报错率会遗漏误报/漏报差异?

图谱连接 : 混淆矩阵