多分类问题中Sklearn计算Precision、Recall、F1结果不符问题
多分类指标计算疑问:Sklearn结果与手动计算不符
我面临一个多分类问题,其中类别0为负类,类别1和2为正类。用Sklearn计算相关指标的代码如下:
import numpy as np from sklearn.metrics import confusion_matrix from sklearn.metrics import ConfusionMatrixDisplay from sklearn.metrics import f1_score from sklearn.metrics import precision_score from sklearn.metrics import recall_score import matplotlib.pyplot as plt # 补充原代码缺失的导入 # 真实标签与预测标签 y_true = np.array((1, 2, 2, 0, 1, 0)) y_pred = np.array((1, 0, 0, 0, 0, 1)) # 计算各项指标 precision_macro = precision_score(y_true, y_pred, average='macro') precision_weighted = precision_score(y_true, y_pred, average='weighted') recall_macro = recall_score(y_true, y_pred, average='macro') recall_weighted = recall_score(y_true, y_pred, average='weighted') f1_macro = f1_score(y_true, y_pred, average='macro') f1_weighted = f1_score(y_true, y_pred, average='weighted') # 绘制混淆矩阵 cm = confusion_matrix(y_true, y_pred) disp = ConfusionMatrixDisplay(confusion_matrix=cm) disp.plot() plt.show()
运行后得到的指标结果:
precision_macro = 0.25 precision_weighted = 0.25 recall_macro = 0.33333 recall_weighted = 0.33333 f1_macro = 0.27778 f1_weighted = 0.27778
对应的混淆矩阵:
我的手动计算过程:
- Precision计算(仅针对类别1和2)
Precision1 = TP1/(TP1+FP1) = 1/(1+1) = 0.5 Precision2 = TP2/(TP2+FP2) = 0/(0+0) = 0(符合Sklearn文档说明) Precision_Macro = (Precision1 + Precision2)/2 = 0.25 Precision_Weighted = (2*Precision1 + 2*Precision2)/4 = 0.25
- Recall计算(仅针对类别1和2)
Recall1 = TP1/(TP1+FN1) = 1/(1+1) = 0.5 Recall2 = TP2/(TP2+FN2) = 0/(0+2) = 0 Recall_Macro = (Recall1+Recall2)/2 = (0.5+0)/2 = 0.25 Recall_Weighted = (2*Recall1+2*Recall2)/4 = (2*0.5+2*0)/4 = 0.25
- F1计算
F1_Macro = 2*(Precision_Macro*Recall_Macro)/(Precision_Macro+Recall_Macro) = 0.25 F1_Weighted = 2*(Precision_Weighted*Recall_Weighted)/(Precision_Weighted+Recall_Weighted) = 0.25
可以看到,手动计算的Precision与Sklearn结果一致,但Recall和F1结果存在差异。即使使用Sklearn给出的Precision(0.25)和Recall(0.3333)也无法得到F1值0.27778,请问我哪里出错了?
问题原因与正确计算方式
你的核心错误是:Sklearn在默认的多分类指标计算中,会包含所有类别(包括你定义的负类0),而你手动计算时只考虑了正类1和2。
1. 先明确混淆矩阵的各项数值(行=真实标签,列=预测标签)
预测0 预测1 预测2 真实0 1 1 0 真实1 1 1 0 真实2 2 0 0
2. 计算每个类别的Precision、Recall、F1
类别0:
- TP0:真实0且预测0 → 1
- FP0:预测0但真实不是0 → 1(真实1)+2(真实2)=3
- FN0:真实0但预测不是0 →1(预测1)
- Precision0 = TP0/(TP0+FP0) =1/(1+3)=0.25
- Recall0 = TP0/(TP0+FN0)=1/(1+1)=0.5
- F1_0 = 2*(0.25*0.5)/(0.25+0.5)= 0.3333
类别1:
- Precision1=0.5,Recall1=0.5,F1_1=0.5
类别2:
- Precision2=0,Recall2=0,F1_2=0(Sklearn中当TP+FP=0时Precision为0,TP+FN=0时Recall为0)
3. 重新计算Macro与Weighted指标
Macro平均(所有类别指标取算术平均):
- Recall_Macro = (Recall0 + Recall1 + Recall2)/3 = (0.5 +0.5 +0)/3 = 1/3 ≈0.33333(与Sklearn结果一致)
- F1_Macro = (F1_0 + F1_1 + F1_2)/3 = (0.3333 +0.5 +0)/3 ≈0.8333/3≈0.27778(与Sklearn结果一致)
Weighted平均(按每个类别的样本数加权):
样本数:类别0有2个,类别1有2个,类别2有2个,总样本6个。
- Recall_Weighted = (20.5 +20.5 +2*0)/6 = (1+1+0)/6=2/6≈0.33333
- F1_Weighted = (20.3333 +20.5 +2*0)/6 = (0.6666+1+0)/6≈1.6666/6≈0.27778
补充说明
如果你只想针对正类1和2计算指标,需要调整Sklearn的参数,限定计算的类别:
# 仅针对类别1和2计算Macro Recall recall_macro_pos = recall_score(y_true, y_pred, average='macro', labels=[1,2]) # 结果会是0.25,和你的手动计算一致
内容的提问来源于stack exchange,提问作者Murilo
相关产品推荐
相关产品推荐

