多类别不平衡分类问题解决方案与实践
2026/4/29 5:59:21 网站建设 项目流程

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 算法偏差问题

大多数分类算法默认假设类别分布均衡,通过优化整体准确率来训练模型。在不平衡数据上,这种假设会导致:

  1. 决策边界向少数类偏移
  2. 少数类样本被当作噪声或异常值
  3. 模型对多数类过拟合
  4. 难以学习少数类的区分性特征

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.451.000.120.23
随机过采样0.780.990.650.71
SMOTE+欠采样0.850.980.760.81
类别权重0.820.970.730.77

5. 常见问题与解决方案

5.1 过采样导致过拟合

现象:验证集表现远差于训练集
解决方案

  1. 使用SMOTE变体如Borderline-SMOTE或SVMSMOTE
  2. 在过采样后添加轻微的高斯噪声
  3. 采用交叉验证评估真实性能

5.2 欠采样丢失重要信息

现象:模型在多数类上表现大幅下降
解决方案

  1. 使用Cluster Centroids代替随机欠采样
  2. 采用集成欠采样方法如EasyEnsemble
  3. 保留多数类的边界样本

5.3 类别权重效果不佳

现象:调整class_weight后改善有限
解决方案

  1. 尝试不同的权重组合,可通过网格搜索优化
  2. 考虑使用自定义损失函数
  3. 检查特征工程是否充分

6. 进阶技巧与经验分享

  1. 分层交叉验证:确保每折都包含所有类别

    from sklearn.model_selection import StratifiedKFold skf = StratifiedKFold(n_splits=5)
  2. 代价矩阵调优:定义误分类代价矩阵并寻找最优组合

    cost_matrix = [[0, 1, 5], # 将类别0预测为其他类的代价 [10, 0, 3], # 将类别1预测为其他类的代价 [8, 2, 0]] # 将类别2预测为其他类的代价
  3. 集成多种方法:例如先使用SMOTE平衡数据,再应用代价敏感学习

  4. 阈值移动:训练后调整决策阈值而非默认的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))]
  5. 异常检测辅助:对极端少数类可先使用异常检测算法如Isolation Forest识别潜在样本

在实际项目中,我发现结合SMOTE过采样和RandomUnderSampler欠采样,配合XGBoost的scale_pos_weight参数调整,通常能在多类别不平衡问题上取得不错的效果。但要注意,不同数据集的最优解决方案可能大不相同,需要系统性地尝试多种方法并通过宏平均F1-score来客观评估。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询