3、分类问题评价:准确率、精确率、召回率、F1分数与混淆矩阵

分类模型好不好,不能光看它猜对了几个。说实话,我刚入行那会儿也犯过这毛病——拿个准确率90%的模型就兴冲冲去上线,结果被产品经理追着骂。为什么?因为数据不平衡的时候,准确率会骗人。

这一章,咱们把分类评价的几把尺子掰开揉碎了讲。你搞懂了它们,以后看模型报告就不会被数字忽悠了。

3.1 混淆矩阵:一切评价的起点

所有分类指标,几乎都是从混淆矩阵算出来的。它就是个2×2的表格,记录着模型预测和真实标签的四种组合情况。

预测为正类 (Positive) 预测为负类 (Negative)
真实为正类 TP (True Positive)
真正例
FN (False Negative)
假负例
真实为负类 FP (False Positive)
假正例
TN (True Negative)
真负例

举个例子。你做个垃圾邮件分类器,模型说「这是垃圾邮件」,结果它确实是——这就是TP。模型说「这不是垃圾」,结果它还真是垃圾——这就是FN,漏掉了。模型说「这是垃圾」,结果是一封正常的工作邮件——FP,误报了。

核心记忆法:TP和TN是「猜对了」,FP和FN是「猜错了」。T/F表示预测对不对,P/N表示模型预测的结果是什么。

下面这张图,把混淆矩阵和四个指标的关系画清楚了。

混淆矩阵与核心评价指标 TP 真正例 预测为正,实际为正 FN 假负例 预测为负,实际为正 FP 假正例 预测为正,实际为负 TN 真负例 预测为负,实际为负 真实 为正 为负 预测为正 预测为负 准确率 = (TP+TN)/(TP+TN+FP+FN) 精确率 = TP/(TP+FP) 召回率 = TP/(TP+FN) F1 = 2·P·R/(P+R)

3.2 准确率:最直观,也最容易翻车

准确率的公式很简单:

Accuracy = (TP + TN) / (TP + TN + FP + FN)

说白了,就是「猜对的比例」。听起来很合理对吧?但问题来了——如果正负样本比例是99:1,你闭着眼睛全猜「负类」,准确率也有99%。

我曾经踩过的坑:做一个信用卡欺诈检测模型,欺诈样本只占0.1%。模型准确率99.9%,我差点就提交报告了。幸好多看了一眼混淆矩阵——好家伙,所有欺诈样本全漏了,一个都没抓住。准确率99.9%,召回率0%。

所以我的建议是:准确率只在正负样本均衡的时候用。如果数据不平衡,别拿它当主要指标。

3.3 精确率:宁缺毋滥

精确率问的是:模型说「是」的那些样本里,有多少是真的「是」?

Precision = TP / (TP + FP)

精确率高,意味着模型很少误报。你想想看,搜索引擎搜「苹果」,出来的全是水果苹果,没有苹果手机——这就是精确率高。

什么时候该追求高精确率?误报代价高的场景。比如垃圾邮件分类,把正常邮件误判成垃圾,用户可能错过重要消息。再比如医疗诊断,把健康人误判成病人,后续检查会浪费大量资源。

3.4 召回率:宁可错杀一千,不可放过一个

召回率问的是:所有真正的「是」里面,模型找出来了多少?

Recall = TP / (TP + FN)

召回率高,意味着模型很少漏掉目标。我在做金融风控的时候,对召回率特别敏感。为什么?因为漏掉一个欺诈交易,可能就是几十万的损失。

什么时候该追求高召回率?漏报代价高的场景。比如癌症筛查,宁可让健康人多做一次检查,也不能漏掉一个早期患者。再比如安防监控,宁可误报几次,也不能让可疑人员溜过去。

一个小技巧:精确率和召回率往往是此消彼长的。你把阈值调低,模型更「激进」,召回率上去了,精确率就下来了。反过来,阈值调高,模型更「保守」,精确率高了,召回率就低了。这个关系叫「Precision-Recall Trade-off」。

3.5 F1分数:精确率和召回率的调和平均

既然精确率和召回率经常打架,总得有个指标来综合评估吧?F1分数就是干这个的。

F1 = 2 * (Precision * Recall) / (Precision + Recall)

注意,它用的是调和平均,不是算术平均。调和平均对较小值更敏感。举个例子:

  • 精确率0.9,召回率0.1,算术平均是0.5,但F1只有0.18
  • 精确率0.5,召回率0.5,算术平均也是0.5,但F1是0.5

你看,F1分数会狠狠惩罚「偏科」的模型。我个人习惯在模型对比时,优先看F1分数。它虽然不是万能的,但至少不会让你被单一指标忽悠。

3.6 多分类场景怎么办?

上面讲的都是二分类。那三分类、十分类呢?

思路其实很简单——把多分类拆成多个「一对多」的二分类。比如三个类别A、B、C,算A的精确率时,把A当正类,B和C当负类。然后有两种聚合方式:

聚合方式 计算方法 适用场景
宏平均 (Macro) 每个类别分别算指标,再取算术平均 各类别同等重要,不考虑样本量
微平均 (Micro) 把所有类别的TP、FP、FN加起来,统一算指标 样本量差异大,希望大类别主导
加权平均 (Weighted) 按每个类别的样本量加权平均 兼顾各类别,同时反映样本分布

举个例子。类别A有1000个样本,类别B只有10个。宏平均会把A和B的指标一视同仁,B的波动会严重影响结果。微平均则基本被A主导。加权平均介于两者之间。

我的建议:做多分类报告时,把宏平均和加权平均都列出来。如果两者差异很大,说明模型在小类别上表现不好,需要进一步分析。

3.7 实战:用Python算一遍

理论说完了,咱们动手。下面这段代码,用sklearn把今天讲的指标全算一遍。

from sklearn.metrics import confusion_matrix, accuracy_score
from sklearn.metrics import precision_score, recall_score, f1_score
from sklearn.metrics import classification_report

# 假设真实标签和预测结果
y_true = [1, 0, 1, 1, 0, 1, 0, 0, 1, 0]
y_pred = [1, 0, 1, 0, 0, 1, 1, 0, 1, 0]

# 混淆矩阵
cm = confusion_matrix(y_true, y_pred)
print("混淆矩阵:")
print(cm)

# 各项指标
acc = accuracy_score(y_true, y_pred)
prec = precision_score(y_true, y_pred)
rec = recall_score(y_true, y_pred)
f1 = f1_score(y_true, y_pred)

print(f"准确率: {acc:.3f}")
print(f"精确率: {prec:.3f}")
print(f"召回率: {rec:.3f}")
print(f"F1分数: {f1:.3f}")

# 一键生成完整报告
print("\n分类报告:")
print(classification_report(y_true, y_pred))

输出结果:

混淆矩阵:
[[3 1]
 [1 5]]
准确率: 0.800
精确率: 0.833
召回率: 0.833
F1分数: 0.833

分类报告:
              precision    recall  f1-score   support
           0       0.75      0.75      0.75         4
           1       0.83      0.83      0.83         6
    accuracy                           0.80        10
   macro avg       0.79      0.79      0.79        10
weighted avg       0.80      0.80      0.80        10

你看,classification_report一行代码,把精确率、召回率、F1、支持度全列出来了,还自动算了宏平均和加权平均。我平时做实验,基本就靠这个函数快速扫一眼模型表现。

3.8 选哪个指标?一张表说清楚

场景 推荐指标 原因
正负样本均衡 准确率 简单直观,够用
正负样本严重不均衡 精确率 + 召回率 + F1 准确率会骗人
误报代价高(宁缺毋滥) 精确率 减少假正例
漏报代价高(宁可错杀) 召回率 减少假负例
需要综合评估 F1分数 平衡精确率和召回率
多分类,各类别样本量差异大 加权平均F1 反映真实分布
多分类,各类别同等重要 宏平均F1 一视同仁

嗯,这一章的内容就到这儿。记住一句话:没有最好的指标,只有最合适的指标。下次拿到一个分类模型,别急着看准确率,先问问自己——这个场景下,漏报和误报,哪个代价更大?想清楚了,指标自然就选对了。