使用 sklearn 计算宏 f1 分数
Posted
技术标签:
【中文标题】使用 sklearn 计算宏 f1 分数【英文标题】:Computing macro f1 score using sklearn 【发布时间】:2017-09-11 07:10:33 【问题描述】:我正在使用sklearn
计算macro f1
分数,我怀疑代码中是否存在任何错误。这是一个示例(标签0
被忽略):
from sklearn.metrics import f1_score, precision_recall_fscore_support
y_true = [1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4]
y_pred = [1, 1, 1, 0, 0, 2, 2, 3, 3, 3, 4, 3, 4, 3]
p_macro, r_macro, f_macro, support_macro \
= precision_recall_fscore_support(y_true=y_true, y_pred=y_pred, labels=[1, 2, 3, 4], average='macro')
p_micro, r_micro, f_micro, support_micro\
= precision_recall_fscore_support(y_true=y_true, y_pred=y_pred, labels=[1, 2, 3, 4], average='micro')
def f(p, r):
return 2*p*r/(p+r)
my_f_macro = f(p_macro, r_macro)
my_f_micro = f(p_micro, r_micro)
print('my f macro '.format(my_f_macro))
print('my f micro '.format(my_f_micro))
print('macro: p , r , f1 '.format(p_macro, r_macro, f_macro))
print('micro: p , r , f1 '.format(p_micro, r_micro, f_micro))
输出:
my f macro 0.6361290322580646
my f micro 0.6153846153846153
macro: p 0.725, r 0.5666666666666667, f1 0.6041666666666666
micro: p 0.6666666666666666, r 0.5714285714285714, f1 0.6153846153846153
如您所见,sklearn
为macro f1
提供0.6041666666666666
。但是,它不等于2*0.725*0.566666666/(0.725+0.566666666)
,其中0.725
和0.566666666
是macro precision
和macro recall
,由sklearn
计算得出。
【问题讨论】:
【参考方案1】:计算“宏观”和“微观”平均值的过程有所不同。
如documentation of f_score:
'micro':通过计算真阳性、假阴性和假阳性的总数来全局计算指标。
'macro':计算每个标签的指标,并找到它们的未加权平均值。这没有考虑标签不平衡。
在宏中,所有类的召回率、精度和 f1 都是单独计算的,然后返回它们的平均值。所以你不能指望在他们身上应用你的公式def f(p, r)
。因为它们和你想的不一样。
在 micro 中,f1 是根据最终精度和召回率计算的(所有类的全局组合)。所以这与您在my_f_micro
中计算的分数相匹配。
希望它有意义。
更多解释,你可以在这里阅读答案:-
How to compute precision, recall, accuracy and f1-score for the multiclass case with scikit learn?【讨论】:
是的,宏是有道理的,但微观呢?它只能用于具有一个类别的布尔分类来“召回”并“精确”吗?什么是假阳性,什么是多个类的假阴性? @TomaszGandor 唯一的区别是计算实际精度、召回率和 f1 的时间。我们首先计算 tp, tn, fp, fn 类。在微观上,我们将所有 tp(对于所有类)求和,其他类相同,然后计算指标。在宏观上,我们首先计算每个类的指标,然后取它们的平均值。希望这能说明问题。以上是关于使用 sklearn 计算宏 f1 分数的主要内容,如果未能解决你的问题,请参考以下文章
在有监督的多类分类中,为啥使用宏 F1 分数而不是平衡精度?