阈值从 0.1 抬到 3.0,精确率从 0.179 升到 1.000,召回从 0.850 掉到 0.020, 误报从 390 个降到 0 个。一个阈值旋钮,四个数一起动,没有免费的方向。
上一节说准确率不够用。 这一节讲第一个替代品:精确率(也叫精度),它专门回答「我抓出来的东西里有多少是对的」。
一、精确率是什么
公式:真正例 ÷(真正例 + 假正例)。分母是「模型判为正类的全部样本」。 换个说法:精确率等于 1 减去误报率(这里的误报率指「判为正的里面错的比例」,不是 FPR)。 它衡量的是「可信度」——模型说「这个有问题」的时候,你有几分能信。 和它配套的是召回率:真正例 ÷(真正例 + 假反例)。分母是「全部真正的正类」。 衡量的是「覆盖率」——该抓的抓到了多少。 两个分母不一样,这是它们永远打架的根源。一个看「判出来的」,一个看「本来该判的」。
二、阈值一动,四个数一起动
模型输出的是分数,要变成「是/否」得定个阈值。Demo 扫了 7 个阈值。 阈值 0.1:命中 85、误报 390、精确率 0.179、召回 0.850、误报率 0.433。 阈值 3.0:命中 2、误报 0、精确率 1.000、召回 0.020、误报率 0.000。 中间是连续的过渡。这就是精确率-召回率权衡曲线:往精确那头走,召回必掉;往召回那头走,精确必掉。 没有一个阈值是「理论上最优」的。要定这个数,必须知道误报和漏报各值多少钱。
三、两个场景,两种选法
垃圾邮件过滤:误报的代价是把一封正常邮件扔进垃圾箱,用户可能漏掉面试通知。 漏报的代价只是多看到一封广告。所以这里要精确率优先,阈值往高定。 癌症筛查:误报的代价是做一次复查,抽个血。漏报的代价是错过治疗窗口。 所以这里要召回率优先,阈值往低定。 同样是二分类,同样是「找一个少见的正类」,阈值方向完全相反。所以定阈值不能看指标,得看业务。 做训练师最常犯的错,是拿一个通用阈值(比如 0.5)套到所有任务上。 0.5 只对「训练时用的损失函数、且两类等代价」的情形有意义,换个场景就该重新定。
四、精确率有个假高陷阱
阈值 3.0 那行精确率是 1.000,看着完美。但它只命中了 2 个。 分母太小的时候,精确率极不稳定。抓到 2 个全对是 1.000,抓到 20 个错 1 个是 0.950——后者其实更可信。 所以看精确率一定要同时看分母(或者看命中数)。只看 1.000 就下结论,等于被小样本骗了。 规范做法是给精确率标一个置信区间,或者干脆要求「命中数不少于 N」才报精确率。 这一点在 AB 测试和小流量场景里特别重要。
五、动手 Demo:阈值扫描:精确率从 0.179 升到 1.000,召回从 0.850 掉到 0.020
造 1000 个样本、正类 100 个(10%),正类打分均值 1.1、负类 0,标准差都是 1; 阈值从 0.1 扫到 3.0 共七档,每档算命中数、误报数、精确率、召回率、误报率。
for th in (0.1, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0):
pred = (score > th).astype(int)
tp = int(((pred == 1) & (y == 1)).sum())
fp = int(((pred == 1) & (y == 0)).sum())
pre = tp / float(tp + fp) if tp + fp else 0.0
rec = tp / float(tp + fn) if tp + fn else 0.0
实跑输出:
--------------------------------------------------------------------
精确率与召回率:阈值一动,两者互换
--------------------------------------------------------------------
样本数 1000,正类 100 个(10%)
打分分布 正类 ~ N(1.1, 1),负类 ~ N(0, 1)
阈值 命中 误报 精确率 召回率 误报率
--------------------------------------------
0.1 85 390 0.179 0.850 0.433
0.5 74 270 0.215 0.740 0.300
1.0 51 136 0.273 0.510 0.151
1.5 34 63 0.351 0.340 0.070
2.0 18 22 0.450 0.180 0.024
2.5 10 5 0.667 0.100 0.006
3.0 2 0 1.000 0.020 0.000
阈值是最直接的旋钮。往下调,命中变多、误报也变多;往上调,两头都变少。
表里看得很清楚:阈值 0.1 时召回 0.850,但误报了 **390** 个,精确率只有 0.179;阈值 3.0 时误报降到 0 个、精确率 1.000,但召回只剩 0.020。
没有一个阈值是「最对的」。选哪个取决于误报和漏报哪个更贵——垃圾邮件过滤可以容忍漏一条,但绝对不能把正常邮件扔进垃圾箱(精确率优先);癌症筛查可以容忍误报,但绝对不能漏(召回率优先)。
这一步是评估里最需要「业务判断」的地方,不是纯技术问题。
注意精确率在阈值 3.0 那行是 1.000,但这个 1.000 建立在只有 2 个命中的基础上——样本太少时精确率会虚高,别被它骗了。
四个数(命中、误报、精确率、召回率)在同一条阈值线上是联动的。 表里每一行都能看出这个联动,没有例外。 阈值 0.1 那行误报 390 个,占总负类的 43.3%——等于「每两个正常样本就误判一个」。 这种模型上线会被用户骂死,但它召回 0.850,指标上看最「全」。 阈值 3.0 那行精确率 1.000,但只命中 2 个。分母太小,这个 1.000 不可信。 中间几行才是实用区间。 真实项目里通常先定一个业务可接受的误报上限(比如误报率不超过 5%), 然后在满足这个上限的阈值里取召回最高的那个。
30 秒实验
- 把正类的打分均值从 1.1 提到 2.0,看还有没有这么陡的权衡曲线。
- 加一条规则:只在误报率不超过 0.05 的阈值里选召回最高的,看会选到哪个阈值。
- 想一想:为什么精确率的分母是「判为正类的数量」,而不是「真正的正类数量」?
常见误区
- 「精确率越高模型越好」——阈值抬到顶,精确率 1.000,但一个正类都抓不到。
- 「阈值 0.5 是标准值」——它只对特定损失函数和等代价场景有意义。
- 「精确率 1.000 就完美了」——命中只有 2 个时,这个数没有统计意义。
自测三问(点开对答案)
1. 精确率怎么算? —— 真正例除以(真正例加假正例),分母是模型判为正类的全部样本。 2. 为什么精确率和召回率会打架? —— 两者分母不同:精确率看判出来的,召回率看本该判出来的,调阈值必然一升一降。 3. 垃圾邮件过滤和癌症筛查该偏向哪个指标? —— 前者偏精确率(怕误杀正常邮件),后者偏召回率(怕漏诊)。精确率和召回率总是打架,那就用一个数把它们合起来。下一节讲 F1。
- ☐ (本节完,下一节 9.1.3 F1分数:更全面地评估分类器的性能)