1. 不平衡分类问题概述

在机器学习实践中,我们经常会遇到类别分布严重不均衡的数据集。比如信用卡欺诈检测中,正常交易可能占99.9%,而欺诈交易仅占0.1%。这种数据特性会导致传统分类算法倾向于预测多数类,忽视少数类,而这恰恰是我们最关心的部分。

Python生态提供了丰富的工具来处理这类问题。过去五年间,我参与过多个金融风控和医疗诊断项目,深刻体会到不平衡分类技术在实际业务中的价值。一个典型的案例是某医疗机构的癌症早期筛查系统,通过合理的采样策略和算法调整,将少数类识别率从60%提升到了85%,同时保持了90%以上的整体准确率。

2. 7天课程核心内容设计

2.1 第一天:理解不平衡数据

我们将从数据探索开始,使用Python的imbalanced-learn和scikit-learn库:

from collections import Counter
from sklearn.datasets import make_classification

# 创建不平衡数据集
X, y = make_classification(n_samples=10000, weights=[0.99], flip_y=0)
print(Counter(y))  # Counter({0: 9900, 1: 100})

关键要掌握两个指标:

  1. 不平衡比(IR):多数类样本数/少数类样本数
  2. 类别分布可视化技巧

注意:不要仅依赖准确率评估模型,在IR=100的数据集上,总是预测多数类就能获得99%的准确率,但这毫无意义。

2.2 第二天:评估指标选择

传统指标失效时,我们需要更合适的评估体系:

指标 公式 适用场景
F1-Score 2*(precision*recall)/(precision+recall) 类别平衡性中等
G-Mean sqrt(recall*specificity) 极端不平衡
MCC (TP TN-FP FN)/sqrt((TP+FP)(TP+FN)(TN+FP)(TN+FN)) 综合评估

建议在项目中同时监控3-4个指标,我通常的实践组合是:ROC-AUC + F1 + 召回率。

2.3 第三天:重采样技术

2.3.1 过采样方法

SMOTE算法原理:

  1. 对每个少数类样本x,找到k个最近邻
  2. 随机选择邻域样本x'
  3. 生成新样本:x_new = x + λ*(x'-x),λ∈[0,1]
from imblearn.over_sampling import SMOTE

smote = SMOTE(sampling_strategy=0.5, k_neighbors=5)
X_res, y_res = smote.fit_resample(X, y)
2.3.2 欠采样技巧

ClusterCentroids的实用技巧:

  • 先进行特征标准化
  • 设置n_clusters≈少数类样本数/10
  • 配合ENN(EditedNearestNeighbours)清洗噪声

2.4 第四天:算法层面解决方案

2.4.1 代价敏感学习

scikit-learn中的class_weight参数实战:

from sklearn.linear_model import LogisticRegression

# 自动计算权重
model = LogisticRegression(class_weight='balanced')

# 手动设置权重
weights = {0:1, 1:10}  # 少数类权重设为10倍
model = LogisticRegression(class_weight=weights)
2.4.2 集成方法优化

BalancedRandomForest的配置要点:

  • 使用strategy='auto'自动平衡
  • max_depth建议设为5-8防止过拟合
  • n_estimators≥200效果更稳定

2.5 第五天:异常检测视角

当IR>100时,可将问题转化为异常检测:

from sklearn.ensemble import IsolationForest

clf = IsolationForest(contamination=0.01)
clf.fit(X_train)
y_pred = clf.predict(X_test)
# 将-1(异常)映射为少数类

2.6 第六天:深度学习方案

用Keras实现加权损失函数:

from tensorflow import keras

def weighted_loss(y_true, y_pred):
    weight = 10.0  # 少数类权重
    loss = keras.losses.binary_crossentropy(y_true, y_pred)
    return tf.reduce_mean(loss * (1 + (weight-1)*y_true))

2.7 第七天:完整项目实战

医疗诊断案例完整流程:

  1. 数据清洗:处理缺失值和异常值
  2. 特征工程:使用SMOTE-NC处理混合数据类型
  3. 模型选择:BalancedBaggingClassifier + XGBoost
  4. 评估:PR曲线为主,ROC曲线为辅
  5. 部署:使用Flask构建API服务

3. 实战经验与避坑指南

3.1 采样策略选择矩阵

数据特点 推荐方法 原因
少量噪声 SMOTE+ENN 避免噪声放大
高维数据 SMOTE-Tomek 降维后采样
类别重叠 Borderline-SMOTE 强化边界样本
极端不平衡 欠采样+集成 防止过拟合

3.2 常见错误排查

  1. 过采样后验证集泄漏:

    • 错误做法:先拆分再分别过采样
    • 正确流程:整体过采样→分层拆分
  2. 代价敏感学习失效:

    • 检查特征尺度是否统一
    • 尝试log变换类别权重
  3. 模型偏向少数类:

    • 调整决策阈值(默认为0.5)
    • 使用CalibratedClassifierCV

4. 进阶技巧与工具链

4.1 自动化调参方案

使用Optuna进行联合优化:

import optuna
from imblearn.pipeline import Pipeline

def objective(trial):
    strategy = trial.suggest_categorical('strategy', ['auto', 'not minority'])
    model = BalancedRandomForestClassifier(
        n_estimators=trial.suggest_int('n_estimators', 50, 500),
        max_depth=trial.suggest_int('max_depth', 3, 10),
        sampling_strategy=strategy
    )
    return cross_val_score(model, X, y, scoring='f1').mean()

study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=50)

4.2 生产环境部署要点

  1. 采样器持久化:
import joblib
smote = SMOTE()
smote.fit(X_train)
joblib.dump(smote, 'smote_model.pkl')  # 保存采样器
  1. 实时预测处理:
  • 在线服务只对模型输入进行采样
  • 使用PySpark进行分布式采样

5. 领域特定解决方案

5.1 金融风控特殊处理

  • 必须保留拒绝推断(reject inference)
  • 使用时间序列交叉验证
  • 关注FPR(False Positive Rate)指标

5.2 医疗诊断注意事项

  • 处理多级不平衡(如癌症分期)
  • 整合临床决策规则
  • 使用Delaunay三角剖分增强采样

在实际项目中,我发现结合业务规则的方法往往比纯算法方案更有效。例如在某信用卡欺诈检测系统中,我们最终采用的方案是:

  1. 规则引擎过滤明显正常交易(约60%)
  2. 对剩余数据使用LightGBM+类别权重
  3. 对模型结果进行人工复核阈值调整

这种混合方法将欺诈检测率提高了40%,同时将误报率降低了25%。关键是要理解没有银弹解决方案,必须根据具体业务场景进行定制化设计。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐