qinghuan
← 回到知识探索

AI 直觉 / 动手实验

准确率 98%,为什么还可能帮不上忙?

用一千张虚构工单数清误报和漏报,看清准确率、精确率与类别比例的区别。

展开本文目录
  1. 先动手看看
  2. 先数四格,再谈模型好不好
  3. 保持两种识别率,改变工单比例
  4. 先确定要解决哪种错误
  5. 记住这三点
  6. 别把例子用过头
  7. 自己试一小步
  8. 查原始资料
  9. 找一份资料继续练
开始前,会这些就够了
  • 理解百分比
遇到不熟悉的词,先看这 2 个解释
基准率
在指定样本或场景中,目标类别本来占多大比例。它描述任务面对的人群或数据构成,而不是模型的识别能力;解释预测结果时,不能把这个比例忽略。
精确率与召回率
先约定要找的目标类别。精确率看“判为目标的里面,有多少真的符合”;召回率看“实际符合的里面,有多少被找出”。两者分母不同,需要结合误报和漏报代价判断。
打开完整术语小抄 ↗

设想一千张练习工单中,只有二十张需要紧急处理。一个程序把所有工单都判成“不紧急”,也能得到百分之九十八的准确率,却一张紧急工单都没找出来。这里的数字完全是自拟数据,用来说明高总分可能掩盖你最关心的那一类错误。

基准率是某类情况在目标人群或数据中本来就有的比例。本例中紧急工单占百分之二。评价一个分类器之前,先看这个比例,再看它到底把哪些样本判对、把哪些判错。

模型标出来的,多少真的符合条件?

1,000 张工单的预期分类结果
真实情况标为紧急标为普通
确实紧急182
实际上普通49931
标为紧急的工单中,确实紧急的比例
26.9%

先只改变紧急工单占比,保持识别能力不动,观察这个比例为什么会变化。

用 1,000 张假设工单观察分类,正类表示“确实需要紧急处理”。按比例计算的是期望数量,表格四舍五入显示;这些输入是教学假设,不是某个产品的准确率。

先数四格,再谈模型好不好

把紧急工单称为正类,可以画出四格:真正紧急且报了警是真正例;普通工单却报警是假正例,也就是误报;紧急工单没报警是假负例,也就是漏报;普通工单没报警是真负例。准确率把两种判对的数量相加,再除以全部工单,所以数量庞大的普通工单会强烈影响它。

召回率只看真正紧急的工单,有多少被找了出来;精确率只看已经报警的工单,有多少真的紧急。两者的分母不同,不能互换。“总共判对多少”和“每次报警多值得相信”也不是同一个问题。若根本没有报警,精确率的分母为零,应明确说明未定义或所用约定,不能悄悄写成满分。

保持两种识别率,改变工单比例

下面构造两组各一千张的计数,假设对紧急工单都找回九成,对普通工单都误报百分之五。第一组有二十张紧急工单,第二组有二百张。代码只做四则运算,没有训练模型,也没有声称现实中换一批数据后,这两种条件识别率仍会保持不变。

第一组中,数量很多的普通工单即使只有一小部分被误报,也能产生不少假警报。第二组的紧急工单更多,报警结果里真紧急的比例便不同。观察输出时,把真正例和假正例一起看,便能理解为什么同一个“找回九成”的说法,还不足以回答“报警后多大比例是真的”。

小实验 · python
cases = {
    "always-normal": (0, 0, 980, 20),
    "rare": (18, 49, 931, 2),
    "more-common": (180, 40, 760, 20),
}
for name, (tp, fp, tn, fn) in cases.items():
    accuracy = (tp + tn) / (tp + fp + tn + fn)
    recall = tp / (tp + fn)
    precision = f"{tp / (tp + fp):.3f}" if tp + fp else "undefined"
    print(name, f"accuracy={accuracy:.3f}",
          f"recall={recall:.3f}", f"precision={precision}")

怎样运行:Python 3.10+;保存为 classification_counts.py,在该目录运行 python classification_counts.py。只用标准库,无需联网。

运行后对照结果
always-normal accuracy=0.980 recall=0.000 precision=undefined
rare accuracy=0.949 recall=0.900 precision=0.269
more-common accuracy=0.940 recall=0.900 precision=0.818

先确定要解决哪种错误

不看输入、始终预测最常见类别,可以作为一个简单基线。它不是有用模型的上限,而是提醒你:复杂模型的成绩需要和合理的起点比较。scikit-learn 的 DummyClassifier 就提供这类基线;实际评估时,基线的选择应来自训练资料,不能先翻看测试答案再挑最有利的规则。

接着把错误接到真实流程:误报会占用多少人工复查时间,漏报会遗漏什么工作。根据这些代价选择阈值,并同时报告样本量、类别比例和关键指标。不能只把准确率下降当成模型变差:一个开始找出紧急工单的模型,可能在增加误报的同时减少漏报,是否值得需要具体判断。

若线上工单的类别比例或内容变化,应重新检查这些计数。这里固定条件识别率只为隔离一个变量;真实系统可能同时发生用词变化、标签规则变化和模型能力变化。单看一个百分比,无法分清是比例变了、阈值变了,还是模型对某类样本的识别变了。

记住这三点

  • 准确率汇总所有样本,可能掩盖少数类的全部漏报。
  • 召回率从实际正类出发,精确率从预测正类出发。
  • 报告基准率、四格计数和错误代价,才能解释分数的用途。

别把例子用过头

  • 一千张工单是自拟计数,不是任何模型的线上准确率。
  • 固定召回率和误报率只是单变量演示,实际分布变化时需要重新测量。
  • 上方代码的三组计数均有正类;没有预测正类时,明确显示精确率未定义。

自己试一小步

同样高的准确率,能否对应不同的人工复查负担?

  1. 自行构造两张总量相同的四格计数表,写清正类含义。
  2. 分别计算准确率、召回率、精确率和报警总量。
  3. 为误报与漏报设置不同的虚构处理成本,再比较两种方案。

做到这些,就算完成

  • 四格数量都是非负整数且能加回总量。
  • 没有把误报率与一减精确率混为一谈。
  • 结论说明了类别比例和成本假设。

查原始资料

想确认一个细节,先看这份资料对应的部分,不必从头读完所有文档。

找一份资料继续练

先选一项,按下面的范围继续学;不必从头读完整门课程。