sklearn计算准确率、召回率、F1

“”"
参考博客:
sklearn计算准确率、精确率、召回率、F1 score
微平均micro,宏平均macro计算方法
“”"

准确率、召回率、F1

对于只有两个标签的任务,即二分类来说,可以将标签分为正类和负类,如下图

真实标签预测标签 正类负类
正类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个二分类问题,每个二分类问题的正类和负类如下表

组号正类负类
白和黑
黄和黑
黄和白

因为我们有3组正类和负类,所以可以计算出三个TP 三个FP 三个FN 三个TN,然后使用micro或者macro的方法计算出一个总的F值~

micro、macro

>>> 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

首先我们来手动计算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中返回的结果一致~

weighted F1

由于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 F1值

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给的结果一致~

应用举例:计算预测结果的top n的f1

“”“预测文件: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

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值