赞
踩
“”"
参考博客:
sklearn计算准确率、精确率、召回率、F1 score
微平均micro,宏平均macro计算方法
“”"
对于只有两个标签的任务,即二分类来说,可以将标签分为正类和负类,如下图
真实标签 | 预测标签 正类 | 负类 |
---|---|---|
正类 | True Positive (TP) | False Negtive (FN) |
负类 | False Positive (FP) | True Negtive (TN) |
precision = TP / (TP + FP)
recall = TP / (TP + FN)
F1 = (precision * recall * 2) / (precesion + recall)
可以将一个多分类问题看作多个二分类问题
比如按照狗的毛色划分为黄色,白色,黑色
于是,我们可以将这个三分类问题分解为3个二分类问题,每个二分类问题的正类和负类如下表
组号 | 正类 | 负类 |
---|---|---|
1 | 黄 | 白和黑 |
2 | 白 | 黄和黑 |
3 | 黑 | 黄和白 |
因为我们有3组正类和负类,所以可以计算出三个TP 三个FP 三个FN 三个TN,然后使用micro或者macro的方法计算出一个总的F值~
>>> from sklearn.metrics import f1_score
>>> y_true = [0, 1, 2, 0, 1, 2]
>>> y_pred = [0, 2, 1, 0, 0, 1]
>>> f1_score(y_true, y_pred, average='macro')
0.26...
>>> f1_score(y_true, y_pred, average='micro')
0.33...
>>> f1_score(y_true, y_pred, average='weighted')
0.26...
>>> f1_score(y_true, y_pred, average=None)
array([0.8, 0. , 0. ])
下面我们手动算一下,看看这几个数字是怎么得出来的
首先我们来手动计算macro F1值
以label 0作为正类,label 1和label 2作为负类, 所对应的TP FN FP TN如下表
真实标签 / 预测标签 | 正类(label 0) | 负类(label 1 和 label 2) |
---|---|---|
正类(label 0) | 2 (TP) | 0 (FN) |
负类(label 1 和 label 2) | 1 (FP) | 3 (TN) |
那么这个表对应的P和R以及F1为:
P = 2 / ( 2 + 1) = 2 / 3
R = 2 / (2 + 0) = 1
F1 = (P * R * 2) / (P + R) = 0.8
类似的,以label 1作为正类,label 0和label 2作为负类
对应的P和R以及F1为:
P = 0 / ( 0 + 2) = 0
R = 0 / (0 + 2) = 0
F1 = 0
以label 2作为正类,label 0和label 1作为负类
对应的P和R以及F1为:
P = 0 / ( 0 + 1) = 0
R = 0 / (0 + 2) = 0
F1 = 0
macro F1 为上述三个F1值的算数平均数,
所以
macro-F1 = (0.8 + 0 + 0) / 3 = 0.26…
这个结果和sklearn中返回的结果一致~
由于macro F1为多个类别的F1值的算数平均数,当样本不平衡的时候,macro F1会给所有类赋予相同的权重
(在sklearn给的上述例子中就是都赋予1 / 3的权重)
在样本不平衡的时候,有时我们希望根据每个类别的样本数量,给不同的类赋予不同的权重,这就是weighted-F1,
例如,假设一共有3个类,它们对应的数量分别为10,5,2
那么,在计算总的F1的时候,我们希望给三个类别的F1值赋予的权重为 10 / 17, 5 / 17, 2 / 17,于是,计算总F1的时候,将会把更多的权重给样本数量多的类.
在sklearn示例代码给的例子中,可以发现label 0,label 1, label 2对应的数量均为2,所以采用macro和weight方式计算的F1值都一样,为0.26
micro采用的方式为,
将三个表格中的所有TP相加,得到总TP = 2 + 0 + 0 = 2
将三个表格中的所有FN相加,得到总FN = 0 + 2 + 2 = 4
将三个表格中的所有FP相加,得到总FP = 1 + 2 + 1 = 4
总P = 总TP / (总TP + 总FP) = 2 / (2 + 4) = 1 / 3
总R = 总TP / (总TP + 总FN) = 2 / (2 + 4) = 1 / 3
总F1 = (总P * 总R * 2) / (总P + 总R) = 1 / 3 = 0.33…
这与sklearn给的结果一致~
“”“预测文件:predict.csv
image_name label predict_1 predict_2 predict_3
a01.jpg 悲伤 愤怒 高兴 中性
a02.jpg 悲伤 高兴 悲伤 中性
a03.jpg 高兴 悲伤 高兴 愤怒
a04.jpg 高兴 悲伤 高兴 中性
a05.jpg 中性 悲伤 愤怒 中性
a06.jpg 中性 中性 高兴 高兴
a07.jpg 愤怒 悲伤 高兴 中性
a08.jpg 愤怒 愤怒 高兴 悲伤
a09.jpg 愤怒 悲伤 中性 愤怒
a10.jpg 愤怒 悲伤 高兴 愤怒
“””
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, classification_report y_true = [0, 1, 2, 0, 1, 2] y_pred = [0, 2, 1, 0, 0, 1] def get_data(): """ 读取预测结果数据,返回真是label和3类top的预测label :return:list: y_true, y_pred1, y_pred2 ,y_pred3, labels """ y_true, y_pred1, y_pred2 ,y_pred3, labels = [], [], [], [], set() with open(file="./predict.csv",mode="r",encoding="utf-8") as f: for line in f.readlines()[1:]: # image_name label predict_1 predict_2 predict_3 samps = [i.strip() for i in line.split("\t")] label = samps[1] y_true.append(label) labels.add(label) y_pred1.append(samps[2]) # 存储top2的预测结果:取predict_1和predict_2预测对的标签,否则取最高分predict_1的标签 y_pred2.append(label if label in samps[2:4] else samps[2]) y_pred3.append(label if label in samps[2:5] else samps[2]) return y_true, y_pred1, y_pred2 ,y_pred3, list(labels) def metric_image(y_true,y_pred,labels): print(f"y_true:{y_true}") print(f"y_pred:{y_pred}") accuracy = accuracy_score(y_true, y_pred) # accuracy = N-correct/N-total print(f"accuracy:{accuracy}") # 0.5 # precision_score = tp / (tp + fp) precision_macro = precision_score(y_true, y_pred, average='macro') precision_micro = precision_score(y_true, y_pred, average='micro') print(f"precision_macro:{precision_macro}") print(f"precision_micro:{precision_micro}") # recall = tp / (tp + fn) recall_macro = recall_score(y_true, y_pred, average='macro') recall_micro = recall_score(y_true, y_pred, average='micro') print(f"recall_macro:{recall_macro}") print(f"recall_micro:{recall_micro}") f1_macro = f1_score(y_true, y_pred, average='macro') f1_micro = f1_score(y_true, y_pred, average='micro') print(f"f1_macro:{f1_macro}") print(f"f1_micro:{f1_micro}\n") # classification_report() 参数说明 # y_true:1 维数组,真实数据的分类标签 # y_pred:1 维数组,模型预测的分类标签 # labels:列表,需要评估的标签名称 # target_names:列表,指定标签名称 # sample_weight:1 维数组,不同数据点在评估结果中所占的权重 # digits:评估报告中小数点的保留位数,如果 output_dict=True,此参数不起作用,返回的数值不作处理 # output_dict:若真,评估结果以字典形式返回 report = classification_report(y_true=y_true,y_pred=y_pred,labels=labels) print(report) if __name__ == '__main__': y_true, y_pred1, y_pred2, y_pred3, labels = get_data() print("前top1 预测的结果:\n") metric_image(y_true, y_pred1, labels) print("前top2 预测的结果:\n") metric_image(y_true, y_pred2, labels) print("前top3 预测的结果:\n") metric_image(y_true, y_pred3, labels)
########################################
前top1 预测的结果:
y_true:[‘悲伤’, ‘悲伤’, ‘高兴’, ‘高兴’, ‘中性’, ‘中性’, ‘愤怒’, ‘愤怒’, ‘愤怒’, ‘愤怒’]
y_pred:[‘愤怒’, ‘高兴’, ‘悲伤’, ‘悲伤’, ‘悲伤’, ‘中性’, ‘悲伤’, ‘愤怒’, ‘悲伤’, ‘悲伤’]
accuracy:0.2
precision_macro:0.375
precision_micro:0.2
recall_macro:0.1875
recall_micro:0.2
f1_macro:0.25
f1_micro:0.20000000000000004
precision recall f1-score support
中性 1.00 0.50 0.67 2
悲伤 0.00 0.00 0.00 2
愤怒 0.50 0.25 0.33 4
高兴 0.00 0.00 0.00 2
avg / total 0.40 0.20 0.27 10
前top2 预测的结果:
y_true:[‘悲伤’, ‘悲伤’, ‘高兴’, ‘高兴’, ‘中性’, ‘中性’, ‘愤怒’, ‘愤怒’, ‘愤怒’, ‘愤怒’]
y_pred:[‘愤怒’, ‘悲伤’, ‘高兴’, ‘高兴’, ‘悲伤’, ‘中性’, ‘悲伤’, ‘愤怒’, ‘悲伤’, ‘悲伤’]
accuracy:0.5
precision_macro:0.675
precision_micro:0.5
recall_macro:0.5625
recall_micro:0.5
f1_macro:0.5714285714285714
f1_micro:0.5
precision recall f1-score support
中性 1.00 0.50 0.67 2
悲伤 0.20 0.50 0.29 2
愤怒 0.50 0.25 0.33 4
高兴 1.00 1.00 1.00 2
avg / total 0.64 0.50 0.52 10
前top3 预测的结果:
y_true:[‘悲伤’, ‘悲伤’, ‘高兴’, ‘高兴’, ‘中性’, ‘中性’, ‘愤怒’, ‘愤怒’, ‘愤怒’, ‘愤怒’]
y_pred:[‘愤怒’, ‘悲伤’, ‘高兴’, ‘高兴’, ‘中性’, ‘中性’, ‘悲伤’, ‘愤怒’, ‘愤怒’, ‘愤怒’]
accuracy:0.8
precision_macro:0.8125
precision_micro:0.8
recall_macro:0.8125
recall_micro:0.8
f1_macro:0.8125
f1_micro:0.8000000000000002
precision recall f1-score support
中性 1.00 1.00 1.00 2
悲伤 0.50 0.50 0.50 2
愤怒 0.75 0.75 0.75 4
高兴 1.00 1.00 1.00 2
avg / total 0.80 0.80 0.80 10
Process finished with exit code 0
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。