F1 得分(Macro-F1与Micro-F1)

对于二分类, F1 得分等于 Precision 与 Recall 的调和平均数, 公式如下:
F 1 - S c o r e = 2 1 P r e c i s i o n + 1 R e c a l l = 2 ∗ P r e c s i o n ∗ R e c a l l P r e c i s i o n + R e c a l l F1\text{-}Score=\frac{2}{\frac{1}{Precision}+\frac{1}{Recall}}=\frac{2*Precsion*Recall}{Precision+Recall} F1-Score=Precision1+Recall12=Precision+Recall2PrecsionRecall

对于多分类, 因为包含多个类别, F1 得分的计算包含 Macro-F1 和 Micro-F1 两种方式


创建示例数据

假设有 “A”, “B”, “C” 三个类别, 作了 16 次预测

import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from sklearn.metrics import f1_score

# 3 种类别
CLASS_NAMES = ("A", "B", "C")

# 16 次预测
state = np.random.RandomState(seed=0)
# 实际标签
labels = state.randint(len(CLASS_NAMES), size=(16,))
# 预测标签
predicts = state.randint(len(CLASS_NAMES), size=(16,))

统计混淆矩阵

# 混淆矩阵
confusion = np.zeros(shape=(len(CLASS_NAMES), len(CLASS_NAMES)), dtype=np.int32)
for i in range(labels.shape[0]):
    confusion[labels[i], predicts[i]] += 1

# 打印混淆矩阵
print("混淆矩阵:", confusion, sep="\n")

结果:

混淆矩阵:
[[2 3 2]
 [2 2 0]
 [1 3 1]]

绘制混淆矩阵

# 绘制混淆矩阵
sns.set()

fig = plt.Figure(figsize=(6.4, 4.8))
ax: plt.Axes = fig.gca()
sns.heatmap(confusion, ax=ax, annot=True, cbar=True, fmt="d")
# X-轴与Y-轴 标签
ax.set_xlabel("Predict")
ax.set_ylabel("Actual")
# 刻度标签
ax.set_xticklabels(CLASS_NAMES)
ax.set_yticklabels(CLASS_NAMES)
# 保存可视化结果
fig.savefig("./confusion.png")

结果:

F1 得分(Macro-F1与Micro-F1)_第1张图片

样本统计(以 A 类别为例)

TP: 预测是 A 类, 实际上也是 A 类

FN: 预测不是 A 类, 实际上是 A 类

FP: 预测是 A 类, 实际上不是 A 类

  1. A 类别
TP FN FP
2 3+2 (第一行除去 A) 2+1 (第一列除去 A)
  1. B 类别
TP FN FP
2 2 6
  1. C 类别
TP FN FP
1 4 2

  1. Macro-F1

计算每一个类别的 Precision 和 Recall

Precision = TP / (TP + FP)

Recall = TP / (TP + FN)

  • A 类别:

Precision = 2 / (2+3) = 0.4

Recall = 2 / (2+5) = 0.286

  • B 类别:

Precision = 2 / (2+6) = 0.25

Recall = 2 / (2+2) = 0.5

  • C 类别:

Precision = 1 / (1+2) = 0.333

Recall = 1 / (1+4) = 0.2

# 准确率(多个类别)
class_p = confusion.diagonal() / confusion.sum(axis=0)
print("class_p:", class_p)
# 召回率(多个类别)
class_r = confusion.diagonal() / confusion.sum(axis=1)
print("class_r:", class_r)

结果

class_p: [0.4        0.25       0.33333333]
class_r: [0.28571429 0.5        0.2       ]

手动计算 Macro-F1

# ---------- 手动计算 Macro F1 ----------

# 防止分母为零
eps = 1e-6
# F1 得分(多个类别)
class_f1 = 2 * class_r * class_p / (class_r + class_p + eps)
print("各类别 F1 得分", class_f1)
# 各类别取平均值
macro_f1 = class_f1.mean()
print("Macro F1:", macro_f1)
各类别 F1 得分 [0.33333285 0.33333289 0.24999953]
Macro F1: 0.3055550891210972

sklearn 验证

print("Macro F1 in sklearn:", f1_score(labels, predicts, average="macro"))
Macro F1: 0.3055550891210972

  1. Micro-F1

计算总体的 Precision 和 Recall, 由此得到总体的 F1-Score

总体样本的统计如下(将各个类别值相加):

TP FN FP
5 11 11

Precision = 5 / (5+11) = 0.3125

Recall = 5 / (5+11) = 0.3125

# ---------- 手动计算 Micro F1 ----------

# 准确率 = 召回率
p = r = confusion.diagonal().sum() / confusion.sum()
print("p or r:", p)
micro_f1 = 2 * r * p / (r + p)
print("Micro F1:", micro_f1)

结果

p or r: 0.3125
Micro F1: 0.3125

总体样本 Precision=Recall=F1-Score

sklearn 验证

print("Micro F1 in sklearn:", f1_score(labels, predicts, average="micro"))
Micro F1 in sklearn: 0.3125

你可能感兴趣的:(DataScience,机器学习)