数据不平衡问题的解决方案

举报
林欣 发表于 2025/11/22 23:31:55 2025/11/22
【摘要】 数据不平衡是机器学习中常见的问题,尤其在分类任务中(如欺诈检测、疾病诊断),某一类别的样本数量远少于其他类别,可能导致模型对多数类过拟合而忽略少数类。以下是系统化的解决方案: 一、数据层面方法 1. 重采样(Resampling)过采样(Oversampling):随机复制:复制少数类样本(可能过拟合)。SMOTE(Synthetic Minority Oversampling Techni...

数据不平衡是机器学习中常见的问题,尤其在分类任务中(如欺诈检测、疾病诊断),某一类别的样本数量远少于其他类别,可能导致模型对多数类过拟合而忽略少数类。以下是系统化的解决方案:


一、数据层面方法

1. 重采样(Resampling)

  • 过采样(Oversampling)

    • 随机复制:复制少数类样本(可能过拟合)。
    • SMOTE(Synthetic Minority Oversampling Technique)
      • 在少数类样本间插值生成新样本(避免简单复制)。
      • 改进版本:Borderline-SMOTE(仅对边界样本插值)、ADASYN(根据密度调整生成权重)。
    • 工具imbalanced-learn库的SMOTE类。
  • 欠采样(Undersampling)

    • 随机删除:删除多数类样本(可能丢失信息)。
    • Tomek Links:删除边界附近的多数类样本(增强类别分离)。
    • NearMiss:保留与少数类最近的多数类样本。
    • 工具imbalanced-learnRandomUnderSamplerTomekLinks
  • 混合采样

    • 结合过采样和欠采样(如先SMOTE过采样少数类,再欠采样多数类)。

2. 生成合成数据

  • GAN(生成对抗网络)
    • 训练GAN生成少数类样本(如CTGAN用于表格数据)。
  • 数据增强
    • 对图像/文本数据应用旋转、同义词替换等操作。

二、算法层面方法

1. 调整分类阈值

  • 默认分类器(如逻辑回归)通常以0.5为阈值,可通过调整阈值偏向少数类:
    from sklearn.linear_model import LogisticRegression
    model = LogisticRegression()
    model.fit(X_train, y_train)
    y_pred = (model.predict_proba(X_test)[:, 1] > 0.3).astype(int)  # 降低阈值
    

2. 代价敏感学习(Cost-Sensitive Learning)

  • 为少数类分配更高的误分类代价:
    • Scikit-learnclass_weight='balanced'(自动调整权重)。
    • XGBoost/LightGBMscale_pos_weight参数(如少数类权重=多数类样本数/少数类样本数)。

3. 集成方法

  • EasyEnsemble
    • 对多数类欠采样多次,训练多个基模型后集成。
  • BalancedBagging
    • 在每轮bootstrap采样时平衡类别分布。
  • 工具imbalanced-learnBalancedBaggingClassifier

4. 异常检测替代

  • 若少数类极端稀少(如欺诈交易占比<1%),可将其视为异常检测问题:
    • 使用Isolation ForestOne-Class SVM

三、评估指标优化

避免使用准确率(Accuracy),改用以下指标:

  • 混淆矩阵:关注真正例(TP)和假负例(FN)。
  • F1-Score:精确率和召回率的调和平均。
  • ROC-AUC:评估模型在不同阈值下的分类能力。
  • PR曲线(Precision-Recall Curve):特别适用于不平衡数据。
  • Cohen’s Kappa:考虑随机猜测的影响。

四、实践流程示例

步骤1:分析数据分布

import pandas as pd
from collections import Counter

df = pd.read_csv("imbalanced_data.csv")
print(Counter(df["target"]))  # 查看类别分布

步骤2:重采样

from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import RandomUnderSampler
from imblearn.pipeline import Pipeline

over = SMOTE(sampling_strategy=0.5)  # 少数类增至多数类的50%
under = RandomUnderSampler(sampling_strategy=0.8)  # 多数类降至80%
steps = [('o', over), ('u', under)]
pipeline = Pipeline(steps=steps)
X_res, y_res = pipeline.fit_resample(X_train, y_train)

步骤3:训练模型并调参

from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report

model = RandomForestClassifier(class_weight='balanced')
model.fit(X_res, y_res)
y_pred = model.predict(X_test)
print(classification_report(y_test, y_pred))  # 重点关注F1和召回率

步骤4:阈值调整(可选)

from sklearn.metrics import precision_recall_curve

probs = model.predict_proba(X_test)[:, 1]
precision, recall, thresholds = precision_recall_curve(y_test, probs)
optimal_idx = np.argmax(precision + recall)  # 选择最佳阈值
optimal_threshold = thresholds[optimal_idx]
y_pred_adjusted = (probs >= optimal_threshold).astype(int)

五、注意事项

  1. 避免数据泄漏
    • 重采样(如SMOTE)只能在训练集上操作,测试集需保持原始分布。
  2. 过采样陷阱
    • SMOTE可能生成噪声样本,建议先清洗数据(如删除重复样本)。
  3. 业务约束
    • 高召回率场景(如癌症诊断)需优先减少假阴性,即使牺牲精确率。
  4. 模型解释性
    • 集成方法(如XGBoost)可能比深度学习更易解释。

六、工具推荐

  • Python库
    • imbalanced-learn:提供多种重采样算法。
    • scikit-learnclass_weight参数、集成方法。
    • XGBoost/LightGBM:内置类别权重调整。
  • 可视化
    • Yellowbrick:绘制PR曲线、混淆矩阵。
    • Seaborn:数据分布统计图。

通过组合上述方法,可显著提升模型在不平衡数据上的性能。建议从简单的代价敏感学习或SMOTE开始,逐步尝试更复杂的集成方法。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。