草稿
召回率
衡量真实正类中有多少被模型找到了。
问题起点:真实 spam 抓了多少?
模型评估了 12 封邮件,你想回答的核心问题是:
在真实为 spam 的邮件里,模型抓到了多少?
立即领取奖品
明显的中奖诱饵,被过滤器拦下。
actual: 垃圾邮件(spam), predicted: 垃圾邮件(spam) (TP: 真正例(true positive))
项目笔记
普通工作邮件,被留在收件箱。
actual: 非垃圾邮件(not-spam), predicted: 非垃圾邮件(not-spam) (TN: 真负例(true negative))
收据已附上
真实收据被错误标成垃圾邮件。
actual: 非垃圾邮件(not-spam), predicted: 垃圾邮件(spam) (FP: 假正例(false positive))
账户提醒
伪造提醒漏进了收件箱。
actual: 垃圾邮件(spam), predicted: 非垃圾邮件(not-spam) (FN: 假负例(false negative))
限时优惠
促销垃圾邮件被正确拦截。
actual: 垃圾邮件(spam), predicted: 垃圾邮件(spam) (TP: 真正例(true positive))
团队午餐
团队日常邮件被正确保留。
actual: 非垃圾邮件(not-spam), predicted: 非垃圾邮件(not-spam) (TN: 真负例(true negative))
密码重置
用户请求的重置邮件正常送达。
actual: 非垃圾邮件(not-spam), predicted: 非垃圾邮件(not-spam) (TN: 真负例(true negative))
紧急转账
诈骗邮件被过滤器漏掉。
actual: 垃圾邮件(spam), predicted: 非垃圾邮件(not-spam) (FN: 假负例(false negative))
航班变更
有用的出行更新被误报。
actual: 非垃圾邮件(not-spam), predicted: 垃圾邮件(spam) (FP: 假正例(false positive))
加密币奖励
可疑奖励垃圾邮件被正确拦截。
actual: 垃圾邮件(spam), predicted: 垃圾邮件(spam) (TP: 真正例(true positive))
发票已批准
业务发票被正确接收。
actual: 非垃圾邮件(not-spam), predicted: 非垃圾邮件(not-spam) (TN: 真负例(true negative))
验证钱包
钓鱼式钱包邮件被漏判。
actual: 垃圾邮件(spam), predicted: 非垃圾邮件(not-spam) (FN: 假负例(false negative))
actual positives = TP + FN = 6
TP 标识: e1, e5, e10
FN 标识: e4, e8, e12
第一种朴素想法:仍用准确率
如果继续用总体正确率:
它告诉你“整体对了多少”,但不回答真实正类覆盖率。
为什么不够:漏报 (FN) 在这个问题里很关键
e4、e8、e12 都是 FN:
e4: 真实是 spam,但预测 not-spam(漏报)e8: 真实是 spam,但预测 not-spam(漏报)e12: 真实是 spam,但预测 not-spam(漏报)
所以对召回率来说,分母是 TP + FN = 6,不是 12。
全部 12 条预测都在分母内。
分子 = TP + TN = 7
Accuracy = 7 / 12 = 58.3%
仅真实正类样本在分母中。
分母 = TP + FN = 6
分子 = TP = 3
Recall = 3/6 = 0.5
真实负类(6): e3, e9, e2, e6, e7, e11
核心发明:看“真实正类”一行
矩阵约定为:
召回率只读真实正类行:
本例:
方向约定:行是实际标签,列是预测标签。
| 真实 \ 预测 | 预测为 spam | 预测为非垃圾 |
|---|---|---|
| 真实 spam | TP (3): e1, e5, e10 | FN (3): e4, e8, e12 |
召回率读取 TP + FN = 6。
来自真实正类行的 TP。
3 (e1, e5, e10)
真实正类行里的 TP + FN。
6 (e1, e5, e10, e4, e8, e12)
Recall = 3/6 = 0.500
含义:6 封真实 spam 中,抓住了 3 封。
交互演示:逐个处理真实正类
交互演示仅处理 e1, e4, e5, e8, e10, e12,按固定顺序逐步给出分子/分母和当前召回率。
真实垃圾邮件召回追踪
e1: 立即领取奖品. 真实标签 垃圾邮件(spam), 预测标签 垃圾邮件(spam). 格子: TP (真正例(true positive)). 捕获正类 1/1, 运行中召回率: 1.0.
1/6
立即领取奖品
e1
垃圾邮件(spam)
垃圾邮件(spam)
TP (真正例(true positive))
1/1
1.0
百分比: 100.0%
3/6 = 0.5
| 步骤 | 邮件 | 主题 | 格子 | 已捕获 | 真实正类已见 | 运行中召回率 | 真实 | 预测 |
|---|---|---|---|---|---|---|---|---|
| 1 | e1 | 立即领取奖品 | TP (真正例(true positive)) | 1 | 1 | 1/1 = 1.0 | 垃圾邮件(spam) | 垃圾邮件(spam) |
| 2 | e4 | 账户提醒 | FN (假负例(false negative)) | 1 | 2 | 1/2 = 0.5 | 垃圾邮件(spam) | 非垃圾邮件(not-spam) |
| 3 | e5 | 限时优惠 | TP (真正例(true positive)) | 2 | 3 | 2/3 = 0.667 | 垃圾邮件(spam) | 垃圾邮件(spam) |
| 4 | e8 | 紧急转账 | FN (假负例(false negative)) | 2 | 4 | 2/4 = 0.5 | 垃圾邮件(spam) | 非垃圾邮件(not-spam) |
| 5 | e10 | 加密币奖励 | TP (真正例(true positive)) | 3 | 5 | 3/5 = 0.6 | 垃圾邮件(spam) | 垃圾邮件(spam) |
| 6 | e12 | 验证钱包 | FN (假负例(false negative)) | 3 | 6 | 3/6 = 0.5 | 垃圾邮件(spam) | 非垃圾邮件(not-spam) |
无 JS 时的账本(与交互一致):
| 步骤 | 邮件 | 主题 | 真实 | 预测 | 格子 | 已捕获正类 | 真实正类已见 | 当前值 |
|---|---|---|---|---|---|---|---|---|
| 1 | e1 | 立即领取奖品 | spam | spam | TP | 1 | 1 | 1/1 = 1 |
| 2 | e4 | 账户提醒 | spam | not-spam | FN | 1 | 2 | 1/2 = 0.5 |
| 3 | e5 | 限时优惠 | spam | spam | TP | 2 | 3 | 2/3 = 0.667 |
| 4 | e8 | 紧急转账 | spam | not-spam | FN | 2 | 4 | 2/4 = 0.5 |
| 5 | e10 | 加密币奖励 | spam | spam | TP | 3 | 5 | 3/5 = 0.6 |
| 6 | e12 | 验证钱包 | spam | not-spam | FN | 3 | 6 | 3/6 = 0.5 |
漏报疼点
召回率直接把漏报放进“真实正类”分母,因此会暴露覆盖损失。
账户提醒
伪造提醒漏进了收件箱。
actual: 垃圾邮件(spam), predicted: 非垃圾邮件(not-spam) (FN: 假负例(false negative))
紧急转账
诈骗邮件被过滤器漏掉。
actual: 垃圾邮件(spam), predicted: 非垃圾邮件(not-spam) (FN: 假负例(false negative))
验证钱包
钓鱼式钱包邮件被漏判。
actual: 垃圾邮件(spam), predicted: 非垃圾邮件(not-spam) (FN: 假负例(false negative))
这些都是真实垃圾邮件但没有被捕获。
漏报数量:3
每个漏报仍然计入分母(FN)。
公式:TP + FN。
零分母约定
当评估集里没有真实正例时:
TP = 0FN = 0TP + FN = 0- 内部值:
null - 渲染结果:
不可用
| 情形 | TP | FN | 分母(TP + FN) | 内部值 | 渲染值 |
|---|---|---|---|---|---|
| 没有真实正类 | 0 | 0 | 0 | null | 不可用 |
实现思路
interface RecallCounts {
tp: number;
fn: number;
}
function recallFromCounts(counts: RecallCounts) {
const denominator = counts.tp + counts.fn;
if (denominator === 0) {
return { numerator: counts.tp, denominator, value: null };
}
return { numerator: counts.tp, denominator, value: counts.tp / denominator };
}
| 步骤 | 分子 (tp) | 分母 (tp + fn) | 分支 | 结果 |
|---|---|---|---|---|
| 1 | tp | tp + fn | 若分母==0 | null |
| 2 | tp | tp + fn | 否则 | tp / (tp + fn) |
正确性直觉
真实正类里只有两种情况,且互斥:
TP: 真实 spam 且预测 spam(被抓)FN: 真实 spam 且预测 not-spam(漏报)
所以 TP + FN 一定等于真实 spam 的数量,当前为 6。
复杂度
- 已有
tp/fn计数时:O(1) - 从示例扫描统计时:
O(n)时间、O(1)额外空间
准确率会计入 TN,而召回率不计 TN/FP。
仅报‘命中了3个’不完整,必须除以全部真实 spam。
精确率问:‘预测为正的有多少对?’
召回率问:‘真实正类有多少被抓到?’
图谱连接
召回率从混淆矩阵的真实正类行派生,可与精确率做边界对照。
已实现
已实现
对照读取不同分母
练习
- 为什么
7/12不是召回率? - 在本例里召回率分母是多少,为什么是这个集合?
- 计算
e8后的运行值。 TP + FN = 0时应如何渲染?- 列出
TP与FN各是什么,分别发生在哪些样本。
| 最终参考 |
|---|
TP + FN = 3 + 3 = 6, 召回率 3 / 6 = 0.5(50%)。 |
| 真实正类样本 |
|---|
e1, e4, e5, e8, e10, e12 |
图谱连接 : 召回率