多分类性能评估方法
- [1. micro-averaging(微平均)](#1. micro-averaging(微平均))
- [2. macro-averaging(宏平均)](#2. macro-averaging(宏平均))
- [3. weighted-averaging(加权平均)](#3. weighted-averaging(加权平均))
在评估多分类模型性能时,我们经常会使用一些指标来衡量其表现。其中,micro-averaging、macro-averaging 和 weighted-averaging 是常见的评估指标之一。它们在衡量分类器的精确度、召回率和 F1 分数时发挥着重要作用。
假设:三分类的真实标签和预测标签如下:
            
            
              python
              
              
            
          
          y_true = ['好评', '好评', '好评', '中评', '中评', '差评', '差评', '差评', '差评', '差评']
y_pred = ['好评', '好评', '好评', '好评', '中评', '差评', '好评', '中评', '差评', '中评']对应的混淆矩阵:
            
            
              python
              
              
            
          
              好评  中评  差评
好评   3   0   0
中评   1   1   0
差评   1   2   2每个类别的评估分数:
            
            
              python
              
              
            
          
          精确率:         [0.6        0.33333333      1.        ]
召回率:         [1.         0.5             0.4       ]
f1-score:     [0.75       0.4             0.57142857]
            
            
              python
              
              
            
          
          from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score
from sklearn.metrics import confusion_matrix
import pandas as pd
if __name__ == '__main__':
    y_true = ['好评', '好评', '好评', '中评', '中评', '差评', '差评', '差评', '差评', '差评']
    y_pred = ['好评', '好评', '好评', '好评', '中评', '差评', '好评', '中评', '差评', '中评']
    # 混淆矩阵
    labels = ['好评', '中评', '差评']
    matrix = confusion_matrix(y_true, y_pred, labels=labels)
    matrix = pd.DataFrame(matrix, columns=labels, index=labels)
    print(matrix)
    print()
    # 返回所有类别分数
    result = precision_score(y_true, y_pred, average=None, labels=['好评', '中评', '差评'])
    print('精确率:\t\t', result)
    result = recall_score(y_true, y_pred, average=None, labels=['好评', '中评', '差评'])
    print('召回率:\t\t', result)
    result = f1_score(y_true, y_pred, average=None, labels=['好评', '中评', '差评'])
    print('f1-score:\t', result)输出即是以上结果
| 缩写 | 全称 | 含义 | 
|---|---|---|
| TP | True Positive(真正) | 实际为正类,模型也预测为正类(正确地预测为正) | 
| FN | False Negative(假负) | 实际为正类,但模型预测为负类(错把正类判为负类) | 
| FP | False Positive(假正) | 实际为负类,但模型预测为正类(错把负类判为正类) | 
| TN | True Negative(真负) | 实际为负类,模型也预测为负类(正确地预测为负) | 
1. micro-averaging(微平均)
做法:将所有类别的 TP、FP、FN 累加,然后再计算 Precision、Recall、F1。
特点 :对每个样本等权处理 ,更关注整体表现。
适用场景:当你希望模型整体上表现好(尤其在样本数差异大时)。
P r e c i s i o n m i c r o = ∑ i = 1 N T P i ∑ i = 1 N ( T P i + F P i ) \displaystyle Precision_{micro}=\dfrac{\sum_{i=1}^{N}TP_i}{\sum_{i=1}^{N}(TP_i+FP_i)} Precisionmicro=∑i=1N(TPi+FPi)∑i=1NTPi
R e c a l l m i c r o = ∑ i = 1 N T P i ∑ i = 1 N ( T P i + F N i ) \displaystyle Recall_{micro}=\dfrac{\sum_{i=1}^{N}TP_i}{\sum_{i=1}^{N}(TP_i+FN_i)} Recallmicro=∑i=1N(TPi+FNi)∑i=1NTPi
F 1 m i c r o = 2 ⋅ P r e c i s i o n m i c r o ⋅ R e c a l l m i r c o P r e c i s i o n m i c r o + R e c a l l m i c r o F1_{micro}=\dfrac{2 \cdot Precision_{micro} \cdot Recall_{mirco}}{Precision_{micro}+Recall_{micro}} F1micro=Precisionmicro+Recallmicro2⋅Precisionmicro⋅Recallmirco
- N N N是类别总数
- T P i TP_i TPi是第 i i i个类的 T P TP TP之和
- F P i FP_i FPi是第 i i i个类的 F P FP FP之和
- F N i FN_i FNi是第 i i i个类的 F N FN FN之和
我们以前面例子为例:
            
            
              python
              
              
            
          
          好评:
TP = 3 (预测为好评且实际为好评)
FP = 1+1 = 2 (预测为好评但实际为中评和差评)
TN = 1+2+2 = 5 (预测不是好评且实际也不是好评,包括中评和差评)
FN = 0+0 = 0 (实际为好评但预测不是好评)
中评:
TP = 1 (预测为中评且实际为中评)
FP = 0+2 = 2 (预测为中评但实际为好评和差评)
TN = 3+2+1+0 = 6 (预测不是中评且实际也不是中评,包括好评和差评)
FN = 1+0 = 1 (实际为中评但预测不是中评)
差评:
TP = 2 (预测为差评且实际为差评)
FP = 0+0 = 0 (没有将其他类别预测为差评)
TN = 3+1+1 = 5 (预测不是差评且实际也不是差评,包括好评和中评)
FN = 1+2 = 3 (实际为差评但预测不是差评)
每个类别的 TP、FP、TN、FN 值分别是:
好评:TP=3, FP=2, TN=5, FN=0
中评:TP=1, FP=2, TN=6, FN=1
差评:TP=2, FP=0, TN=6, FN=3
此时:
TP = 3 + 1 + 2 = 6
FP = 2 + 2 + 0 = 4
TN = 5 + 7 + 6 = 18
FN = 0 + 1 + 3 = 4使用上述计算得到的 TP、FP、TN、FN 值:
- micro-averaged precision :TP/(TP+FP) = 6/(6+4) = 0.6
- micro-averaged recall :TP/(TP+FN) = 6/(6+4) = 0.6
- micro-averaged f1-score :2*(micro-averaged precision * micro-averaged recall) / (micro-averaged precision+micro-averaged recall) = 2*(0.6*0.6)/(0.6+0.6) = 0.6
下面用代码来实现一下
            
            
              python
              
              
            
          
          from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score
if __name__ == '__main__':
    y_true = ['好评', '好评', '好评', '中评', '中评', '差评', '差评', '差评', '差评', '差评']
    y_pred = ['好评', '好评', '好评', '好评', '中评', '差评', '好评', '中评', '差评', '中评']
    result = precision_score(y_true, y_pred, average='micro')
    print('精确率:\t\t', result)
    result = recall_score(y_true, y_pred, average='micro')
    print('召回率:\t\t', result)
    result = f1_score(y_true, y_pred, average='micro')
    print('f1-score:\t', result)可以看到
            
            
              python
              
              
            
          
          精确率:		 0.6
召回率:		 0.6
f1-score:	 0.62. macro-averaging(宏平均)
做法 :先分别计算每个类别的 Precision、Recall、F1,然后对这些类别的指标 取平均。
特点 :每个类别权重相同 ,忽略类别不平衡问题。
适用场景:当你希望模型对所有类别都一样重视时(比如类别数量差不多,但样本数量可能差很多)。
P r e c i s i o n m a c r o = 1 N ∑ i = 1 N T P i T P i + F P i \displaystyle Precision_{macro}=\dfrac{1}{N}\sum_{i=1}^{N}\dfrac{TP_i}{TP_i+FP_i} Precisionmacro=N1i=1∑NTPi+FPiTPi
R e c a l l m a c r o = 1 N ∑ i = 1 N T P i T P i + F N i \displaystyle Recall_{macro}=\dfrac{1}{N}\sum_{i=1}^{N}\dfrac{TP_i}{TP_i+FN_i} Recallmacro=N1i=1∑NTPi+FNiTPi
F 1 m a c r o = 1 N ∑ i = 1 N 2 ⋅ P r e c i s i o n i ⋅ R e c a l l i P r e c i s i o n i + R e c a l l i F1_{macro}=\displaystyle \dfrac{1}{N}\sum_{i=1}^{N}\dfrac{2 \cdot Precision_i \cdot Recall_i}{Precision_i+Recall_i} F1macro=N1i=1∑NPrecisioni+Recalli2⋅Precisioni⋅Recalli
macro-averaging 计算每个类别的精确度、召回率和 F1 分数,然后对它们取算术平均值。
            
            
              python
              
              
            
          
          好评:
精确率:0.6
召回率:1.0
f1-score:0.75
中评:
精确率:0.33
召回率:0.5
f1-score:0.4
差评:
精确率:1
召回率:0.4
f1-score:0.57- macro-averaged precision :(0.6 + 0.33 + 1) / 3 = 0.64
- macro-averaged recall:(1.0 + 0.5 + 0.4) / 3 = 0.63
- macro-averaged f1-score:(0.75 + 0.4 + 0.57) / 3 = 0.57
            
            
              python
              
              
            
          
          from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score
if __name__ == '__main__':
    y_true = ['好评', '好评', '好评', '中评', '中评', '差评', '差评', '差评', '差评', '差评']
    y_pred = ['好评', '好评', '好评', '好评', '中评', '差评', '好评', '中评', '差评', '中评']
    result = precision_score(y_true, y_pred, average='macro')
    print('精确率:\t\t', result)
    result = recall_score(y_true, y_pred, average='macro')
    print('召回率:\t\t', result)
    result = f1_score(y_true, y_pred, average='macro')
    print('f1-score:\t', result)
            
            
              python
              
              
            
          
          精确率:		 0.6444444444444445
召回率:		 0.6333333333333333
f1-score:	 0.57380952380952383. weighted-averaging(加权平均)
做法:先计算每个类别的指标,然后按该类别的样本数占比进行加权平均。
特点 :兼顾类别表现和样本分布,适合处理样本不均衡。
适用场景:样本分布不均时,比 macro 更合理;但仍保留对每类评估的透明度。
假设:共有 100 个样本:
好评:70,精度为:0.3
中评:20,精度为:0.6
差评:10,精度为:0.9
宏平均 = (0.3 + 0.6 + 0.9) / 3 = 0.6
在大多数样本上,模型只有 0.3 的精度,但是宏平均的精度却达到了 0.6。所以,宏平均不能真实的反映出模型在大多数样本上的表现。
weighted-averaging 计算每个类别的精确度、召回率和 F1 分数,然后将它们乘以每个类别的样本数或权重,最后将所有类别的加权平均值。它能够反应出样本在大多数样本上的表现。
加权平均:0.3 * 0.7 + 0.6 * 0.2 + 0.9 * 0.1 = 0.42,由此可以看到加权平均更加能够反映出模型在大多数样本上的表现。
接着前面的例子:
由 y_true = ['好评', '好评', '好评', '中评', '中评', '差评', '差评', '差评', '差评', '差评']
可知每个类别的权重分别为:0.3、0.2、0.5
- weighted-averaged precision:0.6 * 0.3 + 0.33 * 0.2 + 1 * 0.5 = 0.746
- weighted-averaged recall:1 * 0.3 + 0.5 * 0.2 + 0.4 * 0.5 = 0.6
- weighted-averaged f1-score:0.75 * 0.3 + 0.4 * 0.2 + 0.57 * 0.5 = 0.59
            
            
              python
              
              
            
          
          from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score
if __name__ == '__main__':
    y_true = ['好评', '好评', '好评', '中评', '中评', '差评', '差评', '差评', '差评', '差评']
    y_pred = ['好评', '好评', '好评', '好评', '中评', '差评', '好评', '中评', '差评', '中评']
    result = precision_score(y_true, y_pred, average='weighted')
    print('精确率:\t\t', result)
    result = recall_score(y_true, y_pred, average='weighted')
    print('召回率:\t\t', result)
    result = f1_score(y_true, y_pred, average='weighted')
    print('f1-score:\t', result)
            
            
              python
              
              
            
          
          精确率:		 0.7466666666666667
召回率:		 0.6
f1-score:	 0.5907142857142856