先搞清楚:不平衡到什么程度?
y.value_counts(normalize=True)
常见等级
| 正类比例 | 严重程度 |
|---|---|
| 40–60% | 正常 |
| 20–40% | 轻度不平衡 |
| 5–20% | 中度不平衡 |
| <5% | 极度不平衡(风控 / 欺诈 / 交易信号) |
<10% 一定要处理
二、第一原则(非常重要)
不要只看 Accuracy 看这些指标:
| 指标 | 用途 |
|---|---|
| Recall | 抓到多少正类 |
| Precision | 抓到的是不是真 |
| F1 | 平衡指标 |
| ROC-AUC | 排序能力 |
| PR-AUC | 极不平衡时首选 |
from sklearn.metrics import classification_report
print(classification_report(y_true, y_pred))
三、处理方法总览(实战优先级)
方法 1:调整模型权重(首选)
Logistic / SVM / Tree 都支持
from sklearn.linear_model import LogisticRegression
model = LogisticRegression(class_weight="balanced")
优点
- 不破坏数据分布
- 回测稳定
- 金融/风控首选
方法 2:阈值移动(金融非常重要)
默认:
y_pred = (proba > 0.5).astype(int)
调整为:
y_pred = (proba > 0.2).astype(int)
这一步比 SMOTE 更重要
方法 3:下采样(负类太多)
from imblearn.under_sampling import RandomUnderSampler
rus = RandomUnderSampler()
X_res, y_res = rus.fit_resample(X, y)
适合
- 样本极多(百万级)
- 负类冗余
方法 4:上采样 / SMOTE(慎用)
from imblearn.over_sampling import SMOTE
X_res, y_res = SMOTE().fit_resample(X, y)
为什么慎用?
破坏时间序列 金融数据「造假」风险 回测很漂亮,实盘崩
时间序列 / 量化 不建议
方法 5:换模型(树模型天然抗不平衡)
推荐
- XGBoost
- LightGBM
- CatBoost
XGBoost 设置
scale_pos_weight = len(y[y==0]) / len(y[y==1])
xgb.XGBClassifier(
scale_pos_weight=scale_pos_weight,
eval_metric="auc"
)
四、不同场景的最佳实践(你直接抄)
金融 / 量化信号(1 = 进场)
推荐组合
✔ class_weight
✔ 阈值调节
✔ PR-AUC
❌ SMOTE
风控 / 违约 / 欺诈
✔ Recall 优先
✔ PR-AUC
✔ XGBoost + scale_pos_weight
✔ 下采样
医疗 / 事件预测
✔ Recall > Precision
✔ 阈值降低
✔ 成本敏感学习
五、一个完整「标准模板」(强烈推荐)
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score, precision_recall_curve
X_train, X_test, y_train, y_test = train_test_split(
X, y, stratify=y, test_size=0.2
)
model = LogisticRegression(class_weight="balanced")
model.fit(X_train, y_train)
proba = model.predict_proba(X_test)[:,1]
auc = roc_auc_score(y_test, proba)
# 阈值调优
precision, recall, thresholds = precision_recall_curve(y_test, proba)