二分类使用Accuracy和F1-score,多分类使用宏F1和微F1。
最近在使用sklearn做分类时候,用到metrics中的评价函数,其中有一个非常重要的评价函数是F1值,
在sklearn中的计算F1的函数为 f1_score ,其中有一个参数average用来控制F1的计算方式,今天我们就说说当参数取micro和macro时候的区别
对于二分类问题,可将样例根据其真实类别和分类器预测类别划分为:
真正例(True Positive,TP):真实类别为正例,预测类别为正例。
假正例(False Positive,FP):真实类别为负例,预测类别为正例。
假负例(False Negative,FN):真实类别为正例,预测类别为负例。
真负例(True Negative,TN):真实类别为负例,预测类别为负例。
然后可以构建混淆矩阵(Confusion Matrix)如下表所示。
真实类别 |
预测类别 |
|
正例 |
负例 |
|
正例 |
TP |
FN |
负例 |
FP |
TN |
精确率,又称查准率(Precision,P):
召回率,又称查全率(Recall,R):
F1值:
#二分类
from sklearn.metrics import precision_score, recall_score, f1_score
y_true = [0, 1, 1, 0, 1, 0]
y_pred = [1, 1, 1, 0, 0, 1]
Precision = precision_score(y_true, y_pred, average='binary')
recall = recall_score(y_true, y_pred, average='binary')
f1-score = f1_score(y_true, y_pred, average='binary')
如果只有一个二分类混淆矩阵,那么用以上的指标就可以进行评价,没有什么争议,但是当我们在n个二分类混淆矩阵上要综合考察评价指标的时候就会用到宏平均和微平均。
'micro'
:Calculate metrics globally by counting the total true positives, false negatives and false positives.'micro':通过先计算总体的TP,FN和FP的数量,再计算F1
'macro'
:Calculate metrics for each label, and find their unweighted mean. This does not take label imbalance into account.'macro':分布计算每个类别的F1,然后做平均(各类别F1的权重相同)
通过参数用法描述,想必大家从字面层次也能理解他是什么意思,micro就是先计算所有的TP,FN , FP的个数后,然后再利上文提到公式计算出F1
macro其实就是先计算出每个类别的F1值,然后去平均,比如下面多分类问题,总共有1,2,3,4这4个类别,我们可以先算出1的F1,2的F1,3的F1,4的F1,然后再取平均(F1+F2+F3+F4)/4
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]
首先计算总TP值,这个很好就算,就是数一数上面有多少个类别被正确分类,比如1这个类别有3个分正确,2有2个,3有2个,4有1个,那TP=3+2+2+1=8
其次计算总FP值,简单的说就是不属于某一个类别的元数被分到这个类别的数量,比如上面不属于4类的元素被分到4的有1个
如果还比较迷糊,我们在计算时候可以把4保留,其他全改成0,就可以更加清楚地看出4类别下面的FP数量了,其实这个原理就是 One-vs-All (OvA),把4看成正类,其他看出负类
同理我们可以再计算FN的数量
1类 | 2类 | 3类 | 4类 | 总数 | |
TP | 3 | 2 | 2 | 1 | 8 |
FP | 0 | 0 | 3 | 1 | 4 |
FN | 2 | 2 | 1 | 1 | 6 |
所以micro的 精确度P 为 TP/(TP+FP)=8/(8+4)=0.666 召回率R TP/(TP+FN)=8/(8+6)=0.571 所以F1-micro的值为:0.6153
可以用sklearn来核对,把average设置成micro
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]
print(f1_score(y_true,y_pred,labels=[1,2,3,4],average='micro'))
#>>> 0.615384615385
先在各混淆矩阵上分别计算各类的查准率,查全率和F1,然后再计算平均值。
这样就得到“宏查准率”(macro-P)、“宏查全率”(macro-R)、“宏F1”(macro-F1)
正常最终求得就是“宏F1”
1类 | 2类 | 3类 | 4类 | 总数 | |
TP | 3 | 2 | 2 | 1 | 8 |
FP | 0 | 0 | 3 | 1 | 4 |
FN | 2 | 2 | 1 | 1 | 6 |
macro先要计算每一个类的F1,有了上面那个表,计算各个类的F1就很容易了,比如1类,它的精确率P=3/(3+0)=1 召回率R=3/(3+2)=0.6 F1=2*(1*0.5)/1.5=0.75
可以sklearn,来计算核对,把average设置成macro
#average=None,取出每一类的P,R,F1值
p_class, r_class, f_class, support_micro=precision_recall_fscore_support(
y_true=y_true, y_pred=y_pred, labels=[1, 2, 3, 4], average=None)
print('各类单独F1:',f_class)
print('各类F1取平均:',f_class.mean())
#>>>各类单独F1: [ 0.75 0.66666667 0.5 0.5 ]
#>>>各类F1取平均: 0.604166666667
#注意这里,输出《宏F》
print(f1_score(y_true,y_pred,labels=[1,2,3,4],average='macro'))
#>>>0.604166666667
注意:分类报告最后一行为加权平均值。0.64就是加权平均F1-score
https://blog.csdn.net/baidu_38945893/article/details/82141975
f1_score
(y_true, y_pred, labels=None, pos_label=1, average=’binary’, sample_weight=None)
关键参数是 average: string, [None, ‘binary’ (default), ‘micro’, ‘macro’, ‘weighted’, ‘samples’],This parameter is required for multiclass/multilabel targets.
①None:返回每一类各自的f1_score,得到一个array。
②'binary': 只对二分类问题有效,返回由pos_label指定的类的f1_score。
Only report results for the class specified by pos_label. This is applicable only if targets (y_{true,pred}) are binary.
③'micro': 设置average='micro'时,Precision = Recall = F1_score = Accuracy。
注意:这是正确的, 微查准率、微查全率、微F1都等于Accuracy。
下例中为什么不等于?因为预测中有几个0,出现错误了。
Note that for “micro”-averaging in a multiclass setting with all labels included will produce equal precision, recall and F_beta.
Calculate metrics globally by counting the total true positives, false negatives and false positives.
④'macro': 对每一类别的f1_score进行简单算术平均(unweighted mean), with assumption that all classes are equally important。
Calculate metrics for each label, and find their unweighted mean. This does not take label imbalance into account.
⑤'weighted': 对每一类别的f1_score进行加权平均,权重为各类别数在y_true中所占比例。
Calculate metrics for each label, and find their average, weighted by support (the number of true instances for each label). This alters ‘macro’ to account for label imbalance; it can result in an F-score that is not between precision and recall.
⑥'samples':
Calculate metrics for each instance, and find their average (only meaningful for multilabel classification where this differs from accuracy_score).
from sklearn import metrics
y_test = [1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4]
y_predict = [1, 1, 1, 0, 0, 2, 2, 3, 3, 3, 4, 3, 4, 3]
print('准确率:', metrics.accuracy_score(y_test, y_predict)) #预测准确率输出
print('宏平均精确率:',metrics.precision_score(y_test,y_predict,average='macro')) #预测宏平均精确率输出
print('微平均精确率:', metrics.precision_score(y_test, y_predict, average='micro')) #预测微平均精确率输出
print('加权平均精确率:', metrics.precision_score(y_test, y_predict, average='weighted')) #预测加权平均精确率输出
print('宏平均召回率:',metrics.recall_score(y_test,y_predict,average='macro'))#预测宏平均召回率输出
print('微平均召回率:',metrics.recall_score(y_test,y_predict,average='micro'))#预测微平均召回率输出
print('加权平均召回率:',metrics.recall_score(y_test,y_predict,average='micro'))#预测加权平均召回率输出
print('宏平均F1-score:',metrics.f1_score(y_test,y_predict,labels=[1,2,3,4],average='macro'))#预测宏平均f1-score输出
print('微平均F1-score:',metrics.f1_score(y_test,y_predict,labels=[1,2,3,4],average='micro'))#预测微平均f1-score输出
print('加权平均F1-score:',metrics.f1_score(y_test,y_predict,labels=[1,2,3,4],average='weighted'))#预测加权平均f1-score输出
print('混淆矩阵输出:\n',metrics.confusion_matrix(y_test,y_predict))#混淆矩阵输出
print('分类报告:\n', metrics.classification_report(y_test, y_predict))#分类报告输出
准确率: 0.5714285714285714
宏平均精确率: 0.58
微平均精确率: 0.5714285714285714
加权平均精确率: 0.7999999999999999
宏平均召回率: 0.4533333333333333
微平均召回率: 0.5714285714285714
加权平均召回率: 0.5714285714285714
宏平均F1-score: 0.6041666666666666
微平均F1-score: 0.6153846153846153
加权平均F1-score: 0.6369047619047619
混淆矩阵输出:
[[0 0 0 0 0]
[2 3 0 0 0] #[1,0]为2,即1类预测为0的为2。[1,1]为3,则1类预测为1的为3。
[0 0 2 2 0]
[0 0 0 2 1]
[0 0 0 1 1]]
分类报告:
precision recall f1-score support
0 0.00 0.00 0.00 0
1 1.00 0.60 0.75 5
2 1.00 0.50 0.67 4
3 0.40 0.67 0.50 3
4 0.50 0.50 0.50 2
avg / total 0.80 0.57 0.64 14
上例有点问题,因为怎么可能预测为0呢?
from sklearn import metrics
y_test = [1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4]
y_predict = [1, 1, 1, 3, 3, 2, 2, 3, 3, 3, 4, 3, 4, 3]
print('准确率:', metrics.accuracy_score(y_test, y_predict)) #预测准确率输出
print('宏平均精确率:',metrics.precision_score(y_test,y_predict,average='macro')) #预测宏平均精确率输出
print('微平均精确率:', metrics.precision_score(y_test, y_predict, average='micro')) #预测微平均精确率输出
print('加权平均精确率:', metrics.precision_score(y_test, y_predict, average='weighted')) #预测加权平均精确率输出
print('宏平均召回率:',metrics.recall_score(y_test,y_predict,average='macro'))#预测宏平均召回率输出
print('微平均召回率:',metrics.recall_score(y_test,y_predict,average='micro'))#预测微平均召回率输出
print('加权平均召回率:',metrics.recall_score(y_test,y_predict,average='micro'))#预测加权平均召回率输出
print('宏平均F1-score:',metrics.f1_score(y_test,y_predict,labels=[1,2,3,4],average='macro'))#预测宏平均f1-score输出
print('微平均F1-score:',metrics.f1_score(y_test,y_predict,labels=[1,2,3,4],average='micro'))#预测微平均f1-score输出
print('加权平均F1-score:',metrics.f1_score(y_test,y_predict,labels=[1,2,3,4],average='weighted'))#预测加权平均f1-score输出
print('混淆矩阵输出:\n',metrics.confusion_matrix(y_test,y_predict,labels=[1,2,3,4]))#混淆矩阵输出
print('分类报告:\n', metrics.classification_report(y_test, y_predict,labels=[1,2,3,4]))#分类报告输出
输出:
准确率: 0.571428571429
宏平均精确率: 0.696428571429
微平均精确率: 0.571428571429
加权平均精确率: 0.775510204082
宏平均召回率: 0.566666666667
微平均召回率: 0.571428571429
加权平均召回率: 0.571428571429
宏平均F1-score: 0.579166666667
微平均F1-score: 0.571428571429
加权平均F1-score: 0.615476190476
混淆矩阵输出:
[[3 0 2 0]
[0 2 2 0]
[0 0 2 1]
[0 0 1 1]]
分类报告:
precision recall f1-score support
1 1.00 0.60 0.75 5
2 1.00 0.50 0.67 4
3 0.29 0.67 0.40 3
4 0.50 0.50 0.50 2