您很可能使用average='micro' 参数来计算F1 分数。根据docs,将'micro' 指定为平均启动将:
通过计算真阳性、假阴性和假阳性的总数来全局计算指标。
在保证每个测试用例都被分配到一个类的分类任务中,计算微 F1 分数等同于计算准确度分数。看看吧:
from sklearn.metrics import accuracy_score, f1_score
y_true = [[1, 0, 0]]*950 + [[0, 1, 0]]*30 + [[0, 0, 1]]*20
y_pred = [[1, 0, 0]]*1000
print(accuracy_score(y_true, y_pred)) # 0.95
print(f1_score(y_true, y_pred, average='micro')) # 0.9500000000000001
您基本上计算了两次相同的指标。通过指定 average='macro' 代替,将首先独立计算每个标签的 F1 分数,然后取平均值:
print(f1_score(y_true, y_pred, average='macro')) # 0.3247863247863248
如您所见,整体 F1-score 取决于平均策略,小于 0.33 的宏观 F1-score 是模型在预测任务中存在缺陷的明确指标。
编辑:
由于OP询问何时选择哪种策略,并且我认为这对其他人也可能有用,因此我将尝试详细说明此问题。
scikit-learn 实际上为支持多类和多标签分类任务的平均值的指标实现了四种不同的策略。方便的是,classification_report 将返回所有为 Precision、Recall 和 F1-score 申请给定分类任务的人: p>
from sklearn.metrics import classification_report
# The same example but without nested lists. This avoids sklearn to interpret this as a multilabel problem.
y_true = [0 for i in range(950)] + [1 for i in range(30)] + [2 for i in range(20)]
y_pred = [0 for i in range(1000)]
print(classification_report(y_true, y_pred, zero_division=0))
######################### output ####################
precision recall f1-score support
0 0.95 1.00 0.97 950
1 0.00 0.00 0.00 30
2 0.00 0.00 0.00 20
accuracy 0.95 1000
macro avg 0.32 0.33 0.32 1000
weighted avg 0.90 0.95 0.93 1000
根据一个人对班级分布的重视程度,它们都提供了不同的视角。
microaverage 是一种全局策略,基本上忽略了类之间的区别。如果某人真的只对真阳性、假阴性和假阳性方面的整体分歧感兴趣,并且不关心班级内的差异,这可能是有用或合理的。如前所述,如果潜在问题不是多标签分类任务,这实际上等于准确度得分。 (这也是classification_report 函数返回accuracy 而不是micro avg 的原因。
macro average 作为一种策略,将分别计算每个标签的每个指标并返回它们的未加权平均值。如果每个类都具有同等重要性并且结果不应偏向于数据集中的任何类,则这是合适的。
weighted average 也将首先分别计算每个标签的每个指标。但平均值是根据班级的支持度加权的。如果类的重要性与其重要性成正比,则这是可取的,即代表性不足的类被认为不太重要。
samples average 仅对多标签分类有意义,因此在此示例中classification_report 不会返回,此处也不讨论;)
因此,平均策略的选择和结果信任的数量实际上取决于类的重要性。我是否关心类差异(如果没有--> 微观平均),如果是,所有类都同样重要(如果是--> 宏观平均)还是具有更高支持的类更重要(--> 加权平均) .