高加权F1分数与混淆矩阵结果是否一致?Sklearn分类疑问
不平衡分类中加权F1与混淆矩阵的矛盾问题分析
问题背景
现有两类不平衡数据:类别0共35个样本,类别1共364个样本。使用Sklearn进行分类后,得到约0.95的加权F1分数,但混淆矩阵显示类别0样本大多被误判,需要分析两者是否一致及背后原因。
相关代码
交叉验证封装函数
def cv_classif_wrapper(classifier, X, y, n_splits=5, random_state=42, verbose=0): ''' cross validation wrapper ''' cv = StratifiedKFold(n_splits=n_splits, shuffle=True, random_state=random_state) scores = cross_validate(classifier, X, y, cv=cv, scoring=[ 'f1_weighted', 'accuracy', 'recall_weighted', 'precision_weighted']) if verbose: print(f"=====================") print(f"Accuracy: {scores['test_accuracy'].mean():.3f} (+/- {scores['test_accuracy'].std()*2:.3f})") print(f"Recall: {scores['test_recall_weighted'].mean():.3f} (+/- {scores['test_recall_weighted'].std()*2:.3f})") print(f"Precision: {scores['test_precision_weighted'].mean():.3f} (+/- {scores['test_precision_weighted'].std()*2:.3f})") print(f"F1: {scores['test_f1_weighted'].mean():.3f} (+/- {scores['test_f1_weighted'].std()*2:.3f})") return scores
分类调用代码
scores = cv_classif_wrapper(LogisticRegression(), Xs, y0, n_splits=5, verbose=1)
混淆矩阵计算代码
model = LogisticRegression(random_state=42) y_pred = cross_val_predict(model, Xs, y0, cv=5) cm = sklearn.metrics.confusion_matrix(y0, y_pred)
评估结果
Accuracy: 0.952 (+/- 0.051) Recall: 0.952 (+/- 0.051) Precision: 0.948 (+/- 0.062) F1: 0.947 (+/- 0.059)
问题解答
两者结果完全一致,矛盾的核心在于加权类指标的计算逻辑天然偏向样本占比高的类别:
- 类别1的样本占比约91%(364/(35+364)≈0.91),模型只要将绝大多数样本判定为类别1,就能轻松获得极高的加权分数和准确率——哪怕它几乎完全误判了类别0。
- 加权F1的计算方式是:每个类别的F1值乘以该类别的样本占比,再求和。类别0样本量极少,哪怕它的F1值接近0,对整体加权F1的影响微乎其微;而类别1的F1值接近1,乘以高占比后直接拉高了整体分数。
- 同理,加权召回率、加权精确率也遵循相同的加权逻辑,因此即使类别0的召回率极低,整体加权召回率依然能达到0.952。
解决思路
如果需要评估模型对少数类(类别0)的性能,应避免使用加权类指标,改用以下方式:
- 单独计算类别0的F1、召回率、精确率(可通过
sklearn.metrics.f1_score(y_true, y_pred, pos_label=0)实现); - 使用宏平均指标(如
f1_macro),该指标对每个类别赋予相同权重,不受样本量影响; - 使用对类别不平衡更鲁棒的指标,比如ROC-AUC、PR-AUC。
内容的提问来源于stack exchange,提问作者Abolfazl
相关产品推荐
相关产品推荐

