别再只看准确率了!用sklearn的balanced_accuracy_score和f1_score搞定不平衡数据集评估
别再只看准确率了!用sklearn的balanced_accuracy_score和f1_score搞定不平衡数据集评估
记得第一次做信用卡欺诈检测项目时,我训练出的模型准确率高达99.5%,兴奋地汇报给主管后,却被反问:"你知道欺诈交易占数据集的多少吗?"——原来这个"高精度"模型只是把所有交易都预测为正常,而漏掉了全部0.5%的欺诈案例。这个教训让我明白: 在不平衡数据集上,传统准确率是最危险的谎言 。
1. 为什么准确率会欺骗我们?
假设你正在开发一个医疗诊断系统,数据集中健康样本占95%,患者仅占5%。如果一个模型将所有样本都预测为健康,它的准确率会高达95%,但对患者而言这个模型完全失效。这就是 准确率悖论 ——当类别分布严重失衡时,多数类会主导评估结果。
1.1 不平衡数据的典型场景
- 金融风控 :正常交易远多于欺诈交易(通常<1%)
- 医疗诊断 :健康样本远多于患病样本
- 工业质检 :合格品远多于缺陷品
- 自然语言处理 :常见词频远高于罕见词
提示:当少数类占比低于20%时,就应考虑使用平衡指标评估模型
2. 平衡准确率:给每个类别平等发言权
balanced_accuracy_score
的核心思想很简单:
计算每个类别召回率的算术平均值
。这意味着一个包含100个正样本和900个负样本的数据集,正负类的权重都是50%,而非原始比例。
2.1 数学原理与sklearn实现
平衡准确率的计算公式为:
balanced_accuracy = (TP/(TP+FN) + TN/(TN+FP)) / 2
用sklearn计算只需两行代码:
from sklearn.metrics import balanced_accuracy_score
balanced_acc = balanced_accuracy_score(y_true, y_pred)
2.2 实际案例对比
我们用一个信用卡欺诈数据集演示:
| 评估指标 | 模型A(全预测负类) | 模型B(合理预测) |
|---|---|---|
| 传统准确率 | 99.5% | 98.7% |
| 平衡准确率 | 50.0% | 92.3% |
这个对比清晰显示: 传统准确率会奖励作弊行为,而平衡准确率能识别真正有价值的模型 。
3. F1分数:精确率与召回率的和谐统一
F1分数是精确率(Precision)和召回率(Recall)的
调和平均数
,特别适合评估对少数类的识别能力。在sklearn中,
f1_score
的
average
参数有几种关键选择:
3.1 多分类场景下的计算方式
from sklearn.metrics import f1_score
# 宏观平均:所有类别权重相同
macro_f1 = f1_score(y_true, y_pred, average='macro')
# 加权平均:按类别样本量加权
weighted_f1 = f1_score(y_true, y_pred, average='weighted')
3.2 为什么推荐weighted F1?
下表对比了三种平均方式在电商评论情感分析中的应用:
| 情感类别 | 样本占比 | 模型F1 | macro-F1贡献 | weighted-F1贡献 |
|---|---|---|---|---|
| 正面 | 70% | 0.85 | 0.85 | 0.85×0.7=0.595 |
| 中性 | 20% | 0.60 | 0.60 | 0.60×0.2=0.120 |
| 负面 | 10% | 0.40 | 0.40 | 0.40×0.1=0.040 |
| 总分 | 0.62 | 0.62 | 0.755 |
可以看到, weighted F1更贴近实际业务价值 ——它让模型在多数类上的表现贡献更大。
4. 实战:从数据到评估的全流程
让我们用Python完整走一遍处理不平衡数据的流程:
4.1 数据准备与特征工程
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
# 生成不平衡数据集(正负样本比例1:99)
X, y = make_classification(n_samples=10000, weights=[0.99], flip_y=0.01)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
# 使用SMOTE过采样
from imblearn.over_sampling import SMOTE
smote = SMOTE()
X_res, y_res = smote.fit_resample(X_train, y_train)
4.2 模型训练与评估
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import (accuracy_score,
balanced_accuracy_score,
f1_score)
model = RandomForestClassifier()
model.fit(X_res, y_res)
preds = model.predict(X_test)
print(f"准确率: {accuracy_score(y_test, preds):.3f}")
print(f"平衡准确率: {balanced_accuracy_score(y_test, preds):.3f}")
print(f"加权F1: {f1_score(y_test, preds, average='weighted'):.3f}")
4.3 结果可视化技巧
使用混淆矩阵热力图能直观展示模型在不同类别上的表现差异:
import seaborn as sns
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, preds)
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')
5. 进阶技巧与常见陷阱
5.1 阈值调整的艺术
默认0.5的分类阈值可能不适合不平衡数据。通过PR曲线找到最佳阈值:
from sklearn.metrics import precision_recall_curve
import matplotlib.pyplot as plt
probs = model.predict_proba(X_test)[:, 1]
precision, recall, thresholds = precision_recall_curve(y_test, probs)
plt.plot(thresholds, precision[:-1], label='Precision')
plt.plot(thresholds, recall[:-1], label='Recall')
plt.legend()
5.2 避免这些常见错误
- 数据泄露 :在过采样/欠采样前拆分训练测试集
- 指标误用 :在极度不平衡数据上使用micro-F1
- 盲目调参 :先理解业务需求再选择优化方向
5.3 其他实用评估工具
- ROC-AUC :对类别不平衡相对稳健
- Cohen's Kappa :考虑随机猜测的基准
- Matthews系数 :适用于二分类的平衡指标
在最近一个客户流失预测项目中,我们通过组合balanced_accuracy和weighted F1,发现了一个有趣现象:虽然随机森林的准确率比逻辑回归低2%,但它的平衡准确率高出15%,最终这个发现帮助我们选择了真正有效的模型,将高价值客户留存率提升了40%。
更多推荐



所有评论(0)