跳至主要内容

机器学习中的 F1 分数:在精确率与召回率之间取得平衡的指标

了解 F1 分数如何通过结合精确率与召回率来评估模型表现。学习其在二分类与多分类中的用法,并附 Python 示例。
· 6分钟 阅读

使用 AI 探索

在构建由机器学习驱动的模型时,评估模型表现与训练同样重要。尽管准确率常被默认采用,但在类别分布不均的数据集中(某一类占据优势)时,准确率可能具有误导性。

F1 分数是精确率与召回率的调和平均数。它在假阳性与假阴性之间取得平衡,能够更准确地衡量模型表现。

在欺诈检测、医疗诊断、垃圾邮件过滤和故障检测等应用中,仅靠准确率难以呈现全貌。一个模型也许能取得很高的准确率,但如果它无法识别罕见而关键的样本,害处可能大于好处。F1 分数可以覆盖这一风险。如果您还不熟悉评估指标,不妨先在 Machine Learning Fundamentals in Python 中了解基础知识,再继续往下读。

什么是 F1 分数?

F1 分数衡量模型在精确率与召回率之间的平衡。其取值范围为 0 到 1,1 表示精确率与召回率都达到完美,0 则表示表现很差。

  • 精确率用于评估在模型所有正类预测中有多少是真正类。
  • 召回率用于分析在所有真实正类中模型正确识别了多少个。

F1 分数将两者合并为一个数值,并惩罚只在其中一项表现良好的模型。比如,一个模型召回率很高但精确率不佳,可能能正确捕捉全部正类样本,却产生过多的假阳性。F1 指标确保二者被同时考虑。

F1 分数公式与说明

F1 分数的公式是:

F1 score formula

其中,精确率定义为:

precision formula

召回率定义为:

recall formula

此处,TP = 真正类(True Positives),FP = 假正类(False Positives),FN = 假负类(False Negatives)。

之所以使用调和平均数而非算术平均数,是因为前者会惩罚较大的差异。当精确率高但召回率低(或反之)时,F1 分数会显著下降,反映出这种不平衡。

F1 分数 vs. 准确率

准确率衡量在所有预测中有多少是正确的:

在类别平衡的数据集中,准确率较为适用;但在类别不平衡问题中,它会产生误导。

示例:

若某垃圾邮件过滤系统中,90% 为垃圾邮件、10% 为非垃圾邮件,一个将所有邮件都判为“垃圾邮件”的朴素分类器可获得 90% 的准确率,但它从未正确识别非垃圾邮件。在实践中毫无用处。

在这种情况下,F1 指标更为准确,因为它会考虑假阳性和假阴性的代价,而准确率不会。

二分类与多分类中的 F1 分数

二分类

在二分类中,F1 分数是相对于正类计算的。例如,在医学检测中,正类可能代表“患病”。

多分类

在多分类问题中,可以通过不同的平均方式来扩展 F1 分数:ed using averaging methods:

Method

Description

Best for

Macro

分别对每个类别计算 F1,然后取平均。

数据集平衡、各类别等权重。

Weighted

按类别支持度(各类别样本数)加权,对各类别 F1 取加权平均。

不平衡数据集。

Micro

汇总所有类别的贡献以计算整体 F1。

更看重总体表现的情形。

这种灵活性使 F1 分数可以适用于多种分类问题。

如何在 Python 中计算 F1 分数

scikit-learn 库提供了简便的函数来计算 F1 分数。

二分类示例

先评估一个简单的二分类问题,其中预测为 0 或 1。f1_score() 函数可通过真实标签与预测标签直接计算 F1 分数。

from sklearn.metrics import f1_score

# True labels
y_true = [0, 1, 1, 1, 0, 1, 0, 1]

# Predicted labels
y_pred = [0, 1, 0, 1, 0, 1, 1, 1]

# Calculate F1 Score
print("F1 Score:", round(f1_score(y_true, y_pred, average='binary'),2))
F1 Score: 0.8

多分类示例

接下来可将同样的方法扩展到多分类问题,即模型预测的类别超过两个。average 参数控制如何在类别间聚合 F1 分数——常见选项包括 'macro'、'micro' 和 'weighted'。

from sklearn.metrics import f1_score, classification_report

y_true = [0, 1, 2, 2, 0, 1, 2, 1, 2]
y_pred = [0, 2, 1, 2, 0, 0, 2, 1, 2]

# Macro, Micro, Weighted F1
print("Macro F1:", round(f1_score(y_true, y_pred, average='macro'),2))
print("Micro F1:", round(f1_score(y_true, y_pred, average='micro'),2))
print("Weighted F1:", round(f1_score(y_true, y_pred, average='weighted'),2))

# Detailed report
print(classification_report(y_true, y_pred))
Macro F1: 0.65
Micro F1: 0.67
Weighted F1: 0.64
              precision    recall  f1-score   support

           0       0.67      1.00      0.80         2
           1       0.50      0.33      0.40         3
           2       0.75      0.75      0.75         4

    accuracy                           0.67         9
   macro avg       0.64      0.69      0.65         9
weighted avg       0.65      0.67      0.64         9

当我们在多分类或多标签问题中计算 F1 或 Fβ 时,需要决定如何在不同类别间进行平均。scikit-learn 的 average 参数提供了若干选项:

  • Binary:用于两类情形。我们关注正类,优先计算该类别的 precision、recall 和 F1。

  • Micro:将所有类别的贡献汇总后,再计算平均指标。实践中,它先在各类之间汇总真正类、假负类与假正类的总数,再据此计算精确率、召回率与 F1。Micro 平均有助于观察不考虑类别不平衡时的整体表现。

  • Macro:对每个类别分别计算指标,再进行不加权平均。这并不会对各类别提供按样本数加权的处理,因此当各类别同等重要(即使数据集不平衡)时是合理的。

  • Weighted:类似于 Macro,但不会给予每个类别相同权重,而是按每个类别的真实样本数加权。这意味着较大的类别在最终分数中占比更高。当我们希望获得兼顾类别分布的平衡视图时,Weighted 平均很有用。

  • Samples:用于多标签问题(一个样本可属于多个类别)。此时先对每个样本计算指标,再在所有样本间取平均。

这些平均方式使我们能够将 F1 或 Fβ 分数更贴合具体问题场景。例如,在少数类至关重要的罕见疾病分类中,Macro 或 Fβ(其中 β > 1)更为合适;而当我们关注所有类别的整体准确度时,Micro 或 Weighted 平均能提供更好的全貌。

对于更复杂的需求,scikit-learn 还提供了 fbeta_score(),它对 F1 进行了泛化。深入理解此类工具是 Machine Learning Scientist in Python 职业路径的一部分。

用 Fβ 分数泛化 F1 分数

Fβ 分数根据更关注精确率还是召回率,对 F1 分数进行泛化:

  • 𝛃 > 1 时对召回率赋予更高权重。
  • 𝛃 < 1 时更强调精确率。

示例

  • F2 分数适用于医疗诊断,其中漏诊(假阴性)比误报更严重。
  • F0.5 分数更适合垃圾邮件过滤,其中假阳性(把正常邮件误判为垃圾)代价更高。

用例:糖尿病检测中的 F1 vs. 准确率

假设某医疗数据集中,只有 5% 的患者实际患有糖尿病。一个用于糖尿病检测的模型可能拥有 95% 的准确率。但只要始终预测“无糖尿病”,也能轻易达到 95% 的准确率,使该模型变得毫无意义。

因此,我们改用 F1 分数来衡量模型。

from sklearn.metrics import f1_score, fbeta_score, confusion_matrix

# Suppose these are results from a diabetes detection model
y_true = [0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1]  # true outcomes
y_pred = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1]  # model predictions

print("Accuracy:", round((sum([yt == yp for yt, yp in zip(y_true, y_pred)]) / len(y_true)),2))
print("F1 Score:", round(f1_score(y_true, y_pred),2))
print("F2 Score (recall-focused):", round(fbeta_score(y_true, y_pred, beta=2),2))
Accuracy: 0.88
F1 Score: 0.8
F2 Score (recall-focused): 0.71

为何此处选择 F1 或 F2?

  • 由于类别极度不平衡,准确率会产生误导。
  • F1 分数确保同时考虑假阳性(把正常患者误判为糖尿病)与假阴性(未能诊断出糖尿病)。

在该用例中,召回率更为关键,因为漏诊可能改变患者的生命轨迹。因此 F2 分数更为合适,因为它对召回率赋予更高权重。

这表明在临床类用例中,F1 家族的指标比准确率更具实践意义与可用性。

要点回顾

F1 分数提醒我们,模型评估不只是数字游戏,而是要理解每个预测背后的权衡。在真实世界的应用中,漏掉一个关键样本可能会带来严重后果。

随着您不断构建与优化模型,培养对 F1 等指标的直觉,将帮助您在性能判断上做出更符合情境的选择。若想将这些概念应用到真实数据集以深化技能,请查看 Machine Learning Scientist with Python 职业路径,学习如何在多种用例中有效评估、调优与部署模型。

Vidhi Chugh

作者

Vidhi Chugh

我是一名 AI 策略与伦理专家,致力于在数据科学、产品与工程的交汇处构建可扩展的机器学习系统。曾入选全球“200 位顶尖商业与技术创新者”之一,我的使命是让机器学习走向大众,打破术语壁垒,让每个人都能参与这场变革。

常见问题

F1 分数在机器学习中的重要性是什么?

F1 分数是精确率(预测为正的样本中有多少是正确的)与召回率(真实为正的样本中有多少被检测出)的调和平均数。它提供一个同时反映两类错误的单一指标。

为何在不平衡数据集上偏好使用 F1 分数而不是准确率?

当某一类别主导数据时,准确率会具有误导性,因为模型可能对多数类预测良好,却在少数类上表现糟糕。F1 分数同时考虑假阳性与假阴性,因此在这类场景下评估更公平。

F1 与 Fβ 分数有何区别?

F1 分数对精确率与召回率赋予相同权重,而 Fβ 分数允许调整这种平衡。例如,F2 更强调召回率(适用于医疗诊断),F0.5 更偏向精确率(适用于垃圾邮件检测)。

多少的 F1 分数算“好”?

接近 1 的 F1 分数表示精确率与召回率都很强。“好”的标准取决于具体领域。例如,0.8 在医疗领域可能非常出色,但在垃圾邮件检测中可能偏低。

如何在 Python 中计算 F1 分数?

可使用 scikit-learn 的 f1_score() 函数轻松计算 F1 分数。它支持二分类、多分类与多标签设置,并通过 average 参数指定不同的聚合策略。

主题