我之前一直认为F-measure是R和P的调和平均,所以不会存在F1不在P和R之间的情况,后面经人提醒,说sklearn的文档上说This alters ‘macro’ to account for label imbalance; it can result in an F-score that is not between precision and recall.
所以我决定研究一番,发现别有洞天。
下面解释这个问题。我们有 3 个类(猫、鱼、母鸡)和分类器对应的混淆矩阵:
我们先计算每类Precision和Recall。以下是我们三个类别的Precision和Recall
然后计算每个类别的F1 分数。例如,猫的 F1 分数是:
F1 -score(猫)= 2 × (30.8% × 66.7%) / (30.8% + 66.7%) = 42.1%
Macro-F1在sklearn里的计算方法就是计算每个类的F1-score的算数平均值:
Macro-F1 = (42.1% + 30.8% + 66.7%) / 3 = 46.5%
以类似的方式,我们还可以计算宏观平均精度和宏观平均召回率:
Macro-Precision = (31% + 67% + 67%) / 3 = 54.7%
Macro-Recall = (67% + 20% + 67%) / 3 = 51.1%
这种情况下,F1-score的确不在精确度和召回率之间,因为已经这个时候的F1分数已经不是精确度和召回率的调和平均数了。
对Macro-F1进行平均时,我们给每个类赋予相同的权重。而在weighted-F1中,我们通过该类的样本数对每个类的 F1-score 加权。在我们的例子中,我们总共有 25 个样本:6 个猫、10 个鱼和 9 个母鸡。因此,weighted-F1 分数计算如下:
weighted-F1= (6 × 42.1% + 10 × 30.8% + 9 × 66.7%) / 25 = 46.4%
同样,我们可以计算weighted-Precision和weighted-Recall:
weighted-Precision=(6 × 30.8% + 10 × 66.7% + 9 × 66.7%)/25 = 58.1%
weighted-Recall = (6 × 66.7% + 10 × 20.0% + 9 × 66.7%) / 25 = 48.0%
同样的,weighted-F1也不在weighted-Precision和weighted-Recall之间。这也就是为什么sklearn会在文档里提到:
This alters ‘macro’ to account for label imbalance; it can result in an F-score that is not between precision and recall.
显然,计算Macro-F1还可以有一种方式,即先计算Macro-Precision和Macro-Recall,然后再求他们的调和平均数,我用星号 ( *)表示这种计算方法:
Macro-F1*= 2 × (54.7% × 51.1%) / (54.7% + 51.1%) = 52.8%
我们可以看到,Macro-F1 和 Macro-F1* 的值非常不同:46.5% 与 52.8%。
那个那个F1分数才是正确的呢?
在论文A systematic analysis of performance measures for classification tasks里(这篇论文有4000+的引用,我觉得还是比较权威的),作者Sokolova对 Macro-F1的定义如下:
可以看出,Sokolova 论文选择计算 Macro-F1* 而不是 Macro-F1。
相反,在文献“A re-examination of text categorization methods ”里(这篇论文也是4000+的引用),提到的参考文献15是1996 年发表的论文“Training algorithms for linear text classifiers”,其中作者明确指出“Macro-F1是所有类的 F1 的平均值”。
if history is written by the victors, then — like it or not
无论如何,通常大多数不加深思的sklearn使用者,都会直接调用里面的方法。对所有类F1求平均值的Macro-F1计算方法终将成为历史的胜利者,而Macro-F1*将泯然历史。