1. 多类别不平衡分类问题概述
在真实世界的数据分析场景中,我们经常会遇到各类别样本数量严重不均衡的情况。比如在医疗诊断中,健康样本可能占90%而患病样本仅占10%;在金融风控中,正常交易占比99%而欺诈交易不足1%。这种类别分布极度不均衡的数据集会给机器学习模型带来严重挑战。
多类别不平衡分类(Multi-Class Imbalanced Classification)特指类别数量大于2且各类别样本量差异显著时的分类任务。与常见的二分类不平衡问题相比,多类别场景下各类别之间的不平衡程度可能各不相同,某些类别可能同时面临"少数类"和"样本稀疏"双重困境。
2. 核心挑战与技术难点解析
2.1 评估指标陷阱
准确率(Accuracy)在不平衡分类中是完全失效的指标。假设一个数据集中类别A占95%,类别B占3%,类别C占2%,即使模型简单地将所有样本预测为类别A,也能获得95%的"高准确率"。我们需要采用更合理的评估体系:
- 宏平均F1-score(Macro-F1):对每个类别单独计算F1后取平均,平等看待每个类别
- 加权F1-score(Weighted-F1):按类别样本量加权计算F1,反映类别重要性
- 几何平均分数(G-Mean):敏感度(Sensitivity)的特异度(Specificity)的几何平均
- 混淆矩阵可视化:直观展示每个类别的分类情况
2.2 算法偏差问题
大多数分类算法默认假设类别分布均衡,通过优化整体准确率来训练模型。在不平衡数据上,这种假设会导致:
- 决策边界向少数类偏移
- 少数类样本被当作噪声或异常值
- 模型对多数类过拟合
- 难以学习少数类的区分性特征
3. 解决方案与技术实现
3.1 数据层面处理方法
3.1.1 重采样技术
过采样(Over-sampling):
- 随机复制少数类样本(SMOTE基础版)
- SMOTE(Synthetic Minority Over-sampling Technique):在特征空间生成合成样本
- ADASYN:根据样本密度自适应生成合成样本
- 对于多类别问题,需要为每个少数类单独应用过采样
欠采样(Under-sampling):
- 随机删除多数类样本
- Tomek Links:移除边界附近的多数类样本
- Cluster Centroids:对多数类聚类后保留中心点
- 需要谨慎使用以避免丢失重要信息
实操建议:对于多类别问题,建议先对最少的类别进行过采样,再对最多的类别进行欠采样,逐步平衡各类别样本量。
3.1.2 类别权重调整
通过class_weight参数为不同类别分配不同的误分类代价:
from sklearn.utils.class_weight import compute_class_weight classes = np.unique(y_train) weights = compute_class_weight('balanced', classes=classes, y=y_train) class_weight = dict(zip(classes, weights)) model = RandomForestClassifier(class_weight=class_weight)3.2 算法层面改进方法
3.2.1 代价敏感学习
修改损失函数,增加少数类误分类的惩罚:
from sklearn.svm import SVC # 假设我们有3个类别,希望给类别0、1、2分别分配1、2、5的误分类权重 model = SVC(class_weight={0:1, 1:2, 2:5}, probability=True)3.2.2 集成学习方法
- EasyEnsemble:将多数类样本分组成多个子集,每个子集与少数类组合训练基分类器
- BalanceCascade:逐步剔除被正确分类的多数类样本
- RUSBoost:结合随机欠采样和AdaBoost
- SMOTEBoost:在Boosting迭代中应用SMOTE
3.3 新兴深度学习方法
3.3.1 焦点损失(Focal Loss)
通过降低易分类样本的权重,使模型更关注难样本:
import tensorflow as tf def focal_loss(gamma=2., alpha=0.25): def focal_loss_fixed(y_true, y_pred): pt = tf.where(tf.equal(y_true, 1), y_pred, 1-y_pred) return -tf.reduce_mean(alpha * tf.pow(1.-pt, gamma) * tf.math.log(pt)) return focal_loss_fixed model.compile(optimizer='adam', loss=focal_loss(gamma=2, alpha=0.25))3.3.2 类别平衡采样器
from torchsampler import ImbalancedDatasetSampler train_loader = DataLoader( dataset, sampler=ImbalancedDatasetSampler(dataset), batch_size=32 )4. 实战案例:信用卡交易多类别分类
4.1 数据集分析
使用Kaggle信用卡交易数据集:
- 类别0:正常交易(99.8%)
- 类别1:欺诈交易(0.1%)
- 类别2:争议交易(0.1%)
4.2 处理流程实现
# 数据准备 from imblearn.over_sampling import SMOTE from imblearn.under_sampling import RandomUnderSampler from imblearn.pipeline import Pipeline over = SMOTE(sampling_strategy={2:1000, 1:1000}) under = RandomUnderSampler(sampling_strategy={0:10000}) steps = [('o', over), ('u', under)] pipeline = Pipeline(steps=steps) X_resampled, y_resampled = pipeline.fit_resample(X, y) # 模型训练 from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import cross_val_score model = RandomForestClassifier(n_estimators=200, class_weight='balanced') scores = cross_val_score(model, X_resampled, y_resampled, cv=5, scoring='f1_macro') print(f"Macro F1-score: {np.mean(scores):.3f}")4.3 结果对比
| 方法 | Macro-F1 | 类别0 F1 | 类别1 F1 | 类别2 F1 |
|---|---|---|---|---|
| 原始数据 | 0.45 | 1.00 | 0.12 | 0.23 |
| 随机过采样 | 0.78 | 0.99 | 0.65 | 0.71 |
| SMOTE+欠采样 | 0.85 | 0.98 | 0.76 | 0.81 |
| 类别权重 | 0.82 | 0.97 | 0.73 | 0.77 |
5. 常见问题与解决方案
5.1 过采样导致过拟合
现象:验证集表现远差于训练集
解决方案:
- 使用SMOTE变体如Borderline-SMOTE或SVMSMOTE
- 在过采样后添加轻微的高斯噪声
- 采用交叉验证评估真实性能
5.2 欠采样丢失重要信息
现象:模型在多数类上表现大幅下降
解决方案:
- 使用Cluster Centroids代替随机欠采样
- 采用集成欠采样方法如EasyEnsemble
- 保留多数类的边界样本
5.3 类别权重效果不佳
现象:调整class_weight后改善有限
解决方案:
- 尝试不同的权重组合,可通过网格搜索优化
- 考虑使用自定义损失函数
- 检查特征工程是否充分
6. 进阶技巧与经验分享
分层交叉验证:确保每折都包含所有类别
from sklearn.model_selection import StratifiedKFold skf = StratifiedKFold(n_splits=5)代价矩阵调优:定义误分类代价矩阵并寻找最优组合
cost_matrix = [[0, 1, 5], # 将类别0预测为其他类的代价 [10, 0, 3], # 将类别1预测为其他类的代价 [8, 2, 0]] # 将类别2预测为其他类的代价集成多种方法:例如先使用SMOTE平衡数据,再应用代价敏感学习
阈值移动:训练后调整决策阈值而非默认的0.5
from sklearn.calibration import calibration_curve prob_pos = model.predict_proba(X_test)[:, 1] fop, mpv = calibration_curve(y_test, prob_pos, n_bins=10) optimal_threshold = mpv[np.argmin(np.abs(fop-mpv))]异常检测辅助:对极端少数类可先使用异常检测算法如Isolation Forest识别潜在样本
在实际项目中,我发现结合SMOTE过采样和RandomUnderSampler欠采样,配合XGBoost的scale_pos_weight参数调整,通常能在多类别不平衡问题上取得不错的效果。但要注意,不同数据集的最优解决方案可能大不相同,需要系统性地尝试多种方法并通过宏平均F1-score来客观评估。