机器学习不平衡分类实战:7天掌握关键技术与Python实现
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})
关键要掌握两个指标:
- 不平衡比(IR):多数类样本数/少数类样本数
- 类别分布可视化技巧
注意:不要仅依赖准确率评估模型,在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算法原理:
- 对每个少数类样本x,找到k个最近邻
- 随机选择邻域样本x'
- 生成新样本: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 第七天:完整项目实战
医疗诊断案例完整流程:
- 数据清洗:处理缺失值和异常值
- 特征工程:使用SMOTE-NC处理混合数据类型
- 模型选择:BalancedBaggingClassifier + XGBoost
- 评估:PR曲线为主,ROC曲线为辅
- 部署:使用Flask构建API服务
3. 实战经验与避坑指南
3.1 采样策略选择矩阵
| 数据特点 | 推荐方法 | 原因 |
|---|---|---|
| 少量噪声 | SMOTE+ENN | 避免噪声放大 |
| 高维数据 | SMOTE-Tomek | 降维后采样 |
| 类别重叠 | Borderline-SMOTE | 强化边界样本 |
| 极端不平衡 | 欠采样+集成 | 防止过拟合 |
3.2 常见错误排查
-
过采样后验证集泄漏:
- 错误做法:先拆分再分别过采样
- 正确流程:整体过采样→分层拆分
-
代价敏感学习失效:
- 检查特征尺度是否统一
- 尝试log变换类别权重
-
模型偏向少数类:
- 调整决策阈值(默认为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 生产环境部署要点
- 采样器持久化:
import joblib
smote = SMOTE()
smote.fit(X_train)
joblib.dump(smote, 'smote_model.pkl') # 保存采样器
- 实时预测处理:
- 在线服务只对模型输入进行采样
- 使用PySpark进行分布式采样
5. 领域特定解决方案
5.1 金融风控特殊处理
- 必须保留拒绝推断(reject inference)
- 使用时间序列交叉验证
- 关注FPR(False Positive Rate)指标
5.2 医疗诊断注意事项
- 处理多级不平衡(如癌症分期)
- 整合临床决策规则
- 使用Delaunay三角剖分增强采样
在实际项目中,我发现结合业务规则的方法往往比纯算法方案更有效。例如在某信用卡欺诈检测系统中,我们最终采用的方案是:
- 规则引擎过滤明显正常交易(约60%)
- 对剩余数据使用LightGBM+类别权重
- 对模型结果进行人工复核阈值调整
这种混合方法将欺诈检测率提高了40%,同时将误报率降低了25%。关键是要理解没有银弹解决方案,必须根据具体业务场景进行定制化设计。
更多推荐


所有评论(0)