4. Fβ-Score 与加权 F1:平衡的艺术

说到分类模型的评价,F1 值大家肯定不陌生。但现实问题里,精确率和召回率的重要性能完全一样吗?

我个人习惯用 Fβ-Score 来解决这个矛盾。说白了,就是给它一个「偏心」参数 β,让你自己决定更看重哪一头。这一章我就带你把 β 参数、宏/微/加权平均这些概念彻底理清楚。

4.1 Fβ-Score 公式与 β 的含义

先看标准定义:

Fβ = (1 + β²) × (Precision × Recall) / (β² × Precision + Recall)

这个公式里 β 是个大于 0 的实数。β 的作用是什么?我拆开给你看:

β 取值偏向业务场景举例
β < 1更看重精确率垃圾邮件过滤(误拦比漏过更严重)
β = 1精确率=召回率,即标准 F1一般平衡场景
β > 1更看重召回率癌症筛查(漏诊比误诊更危险)

β 越大,召回率的权重越高。我曾经在一个项目里需要设计医疗图像检测模型,漏诊率要求极低,当时直接把 β 设成了 2,效果明显比 F1 更贴近业务目标。

小技巧: β 通常取 0.5、1、2 三个常用值。不用精确到小数点后那么多,那是过度优化。

4.2 多分类下的 Fβ:三种平均方式

单二分类用 Fβ 很简单。但到了多分类(比如识别猫、狗、鸟),就要算每个类别的 Fβ,然后做平均。教科书上给了三种方式:宏平均、微平均、加权平均。我当年刚接触时也被绕晕过,咱们一个个说。

4.2.1 宏平均(Macro Average)

先分别算每个类别的 Fβ,再直接取算术平均。举个例子,三类:

Fβ_cat = 0.85
Fβ_dog = 0.72
Fβ_bird = 0.90

宏平均 Fβ = (0.85 + 0.72 + 0.90) / 3 = 0.823

宏平均给了每个类别相同的权重——哪怕某个类样本极少,也和样本多的类一样重要。这种做法在小类上很敏感,如果某个类本来就难分,宏平均会被明显拉低。

适用场景: 每个类别都同等重要,不关心样本不平衡。比如多标签分类任务中,罕见类别也很关键。

4.2.2 微平均(Micro Average)

微平均把所有类别的 TP、FP、FN 先汇总,再统一算 Fβ。公式如下:

Micro Precision = ΣTP / (ΣTP + ΣFP)
Micro Recall    = ΣTP / (ΣTP + ΣFN)
Micro Fβ = (1+β²) × (Micro P × Micro R) / (β² × Micro P + Micro R)

你想想看,微平均其实受大类的支配。因为我有一个三分类问题,猫的样本占了 90%,狗和鸟各 5%。微平均 Fβ 几乎就被猫的表现决定了,狗和鸟好不好根本没权重。

我遇到过一位同事,发现模型精确率 98%,但用宏平均一算只有 65%,原来是把大类做得好、小类全挂了。微平均在严重不平衡时容易欺骗你。

避坑指南: 千万不要在极度不平衡的数据集上只用微平均。我曾经上报了一个模型准确率 99%,结果上线后对稀有种类的识别率接近 0,就是因为只看了微平均。

4.2.3 加权平均(Weighted Average)

加权平均是宏平均的改良版。每个类别按样本数占比加权:

加权 Fβ = Σ(类别权重 × Fβ_i)
其中 类别权重 = 该类样本数 / 总样本数

回到刚才的例子,猫占 90%,狗 5%,鸟 5%。假如 Fβ 分别是 0.98、0.50、0.40:

加权 Fβ = 0.90×0.98 + 0.05×0.50 + 0.05×0.40 = 0.882 + 0.025 + 0.020 = 0.927

这个值更接近真实业务中整体感知的质量——毕竟大部分预测是对猫进行的。加权平均是 scikit-learn 里很多函数的默认选项,嗯,这里有讲究的。

4.3 三者对比一览

指标计算方式对不平衡的态度推荐场景
宏平均各类 Fβ 等权平均小类影响大每个类别同等重要
微平均汇总混淆矩阵再算大类主导整体预测质量(忽略小类)
加权平均各类 Fβ 按样本比例加权折中,偏向大类实际业务上线首选

我个人的习惯是:拿到一个多分类任务,先同时算出这三种平均,比较差异。如果宏平均远低于加权平均,基本可以断定小类出了问题。这时候我就会进一步检查每个类别的混淆矩阵。

4.4 代码示例:用 sklearn 计算 Fβ 与三种平均

下面这段代码我用的是 scikit-learn 的 fbeta_score 函数,可以非常方便地指定 β 和 average 参数:

from sklearn.metrics import fbeta_score, classification_report

y_true = [0, 0, 0, 0, 0, 1, 1, 1, 2, 2]  # 0:90%的猫, 1:狗, 2:鸟
y_pred = [0, 0, 0, 0, 0, 1, 1, 2, 2, 0]   # 故意把鸟误判为猫

# F2 召回率更重要
macro_f2 = fbeta_score(y_true, y_pred, beta=2, average='macro')
micro_f2 = fbeta_score(y_true, y_pred, beta=2, average='micro')
weighted_f2 = fbeta_score(y_true, y_pred, beta=2, average='weighted')

print(f"Macro F2: {macro_f2:.3f}")
print(f"Micro F2: {micro_f2:.3f}")
print(f"Weighted F2: {weighted_f2:.3f}")

# 更详细的分类报告
print("\n分类报告(F1 基准):")
print(classification_report(y_true, y_pred, digits=3))

输出的结果你就看到了:宏平均因为鸟(2类)的 F1 极低被拉了很多;微平均由于猫类大量正确而很高;加权平均介于之间。这个差异正是我们前面讨论的。

4.5 一张图总结本章知识体系

下面我把 Fβ-Score 与三种平均的关系画成了一个流程图,方便你一眼看清脉络。

Fβ-Score 与三种平均的知识体系 Fβ-Score β:控制精确率与召回率的权重 β < 1(重精确率) β = 1(F1 平衡) β > 1(重召回率) 多分类:三种平均方式 宏平均 各类等权 微平均 汇总混淆矩阵 加权平均 按样本比例加权 核心:β 调整单类权重,多类后通过宏/微/加权平均汇总

4.6 避坑指南与个人经验

我见过不少新手直接调用 f1_score(y_true, y_pred, average='macro') 就交差。嗯,这其实挺危险的。说说我踩过的坑:

  • 曾经在做垃圾短信分类时,我用了宏平均 F1 来选模型,结果选出了一个对正常短信误杀率极低的模型,但垃圾短信的召回率也低得可怜——因为宏平均里两类权重一样,正常短信数量大但权重被“虚高”了。后来改成加权平均才找到真正适合业务的那个模型。
  • 还有一个教训:在医学影像多标签分类中,我用微平均 F2(β=2)来评估,结果模型对罕见病变几乎没检出,但微平均被主流标签的召回率拉高,看上去绩效很好——直到上会后被医生质疑。从那以后,我每次都会同时打印宏平均和加权平均,并在报告里标注样本分布。
我的推荐组合:
  • 报告实验时:同时输出宏平均、加权平均、每个类的 Fβ,以及样本数。
  • 业务选型:使用加权平均 + 合适的 β(β 值根据业务对漏报/误报的容忍度定)。
  • 调试阶段:关注宏平均的波动,它能快速暴露小类问题。

4.7 小结

Fβ-Score 给了你一把调节精确率与召回率的旋钮,而宏/微/加权平均则是把多分类结果汇总成单一数字的三种不同视角。没有哪个永远是“最好”的,关键是你得知道自己当前的任务想强调什么。