使用imblearn采样前须检查标签分布,确保y为数值型且无空值或混合类型;smote不支持多输出和字符串标签,需预处理;高维稀疏特征下慎用smote,优先降维或改用adasyn/smotenc;采样必须仅在训练集内、cv每折中进行以防数据泄露;评估应关注少数类precision/recall/f1及auc,并设zero_division=0避免nan。

用 imblearn 做过采样前必须检查标签分布
直接调 SMOTE().fit_resample() 很容易忽略原始数据中是否存在标签为字符串或空值的情况。一旦 y 里混着 "unknown" 或 None,SMOTE 会报 ValueError: Expected array of shape (n_samples,) but got shape (n_samples, 1) 这类看似维度错误、实则类型异常的提示。
实操建议:
- 先跑
print(pd.Series(y).value_counts(dropna=False)),确认所有标签都是整数或一致字符串(如全为"fraud"/"normal") - 若含字符串标签,必须用
sklearn.preprocessing.LabelEncoder或pd.Categorical(y).codes转成数值型再进采样流程 -
SMOTE不支持多输出(multi-output y),如果y.shape[1] > 1,得先 flatten 或改用SMOTEN(仅支持标称型)或SMOTENC(混合类型)
RandomOverSampler 和 SMOTE 的选择取决于特征空间是否线性可分
RandomOverSampler 简单复制少数类样本,速度快、无额外依赖,但容易导致过拟合——尤其当原始少数类样本本身就集中在某几个异常点附近时,复制只会放大噪声。
SMOTE 在特征空间中对相邻样本插值生成新样本,隐含假设是:少数类在局部区域具有连续性。但如果特征是高维稀疏的(比如 one-hot 后的类别变量超过 50 维),欧氏距离失效,SMOTE 生成的“新样本”可能落在毫无意义的区域。
实操建议:
- 先用
PCA(n_components=5)降维后画散点图,观察少数类是否大致连成片;如果不是,优先用RandomOverSampler或考虑ADASYN(更关注边界样本) - 对含大量分类特征的数据,改用
SMOTENC并显式传入categorical_features索引,否则默认按连续变量处理会出错 - 别在 pipeline 里对全量数据 fit
SMOTE—— 必须只在训练集上做,且要和StandardScaler一样放在交叉验证的每折内,否则造成数据泄露
评估指标不能只看准确率,classification_report 要强制指定 zero_division
类别极度不平衡时,模型全预测多数类也能拿到 99%+ 准确率,但实际毫无价值。必须看 precision、recall、f1-score,尤其是少数类(如正例)的 recall(查全率),它直接反映漏检风险。
常见坑是:当某类样本在某个 CV 折中完全没出现,classification_report 默认抛 UndefinedMetricWarning 并跳过该类统计,导致 f1 计算失真。例如测试集里没有正例,recall 就变成 nan,后续取平均会出错。
实操建议:
- 统一用
classification_report(y_true, y_pred, zero_division=0),把 nan 替换为 0,保证指标可比 - 加一行
from sklearn.metrics import roc_auc_score; roc_auc_score(y_true, y_proba[:, 1]),AUC 对类别比例不敏感,更适合不平衡场景 - 如果业务更怕误杀(比如风控拒绝正常用户),重点盯
precision;更怕漏抓(比如疾病筛查),重点盯recall—— 指标选择得贴业务,不是套模板
欠采样不是“删多数类就完事”,RandomUnderSampler 需配合清洗
RandomUnderSampler 随机丢弃多数类样本,看似简单,但极可能把有信息量的边界样本一起删掉,导致决策边界偏移。更危险的是:如果多数类本身含噪声(比如标注错误的“正常”样本被当成负例),随机下采样反而保留了这些脏数据。
实操建议:
- 先用
OneClassSVM或IsolationForest对多数类单独做异常检测,把得分低的样本标记出来,下采样时优先剔除它们 - 改用
EditedNearestNeighbours(ENN)或RepeatedEditedNearestNeighbours(RENNS),它们会删除那些与其近邻类别不一致的多数类样本,本质是清洗+欠采样一体化 - 注意
ENN对 k 值敏感:k 太小易删太多,k 太大则清洗不彻底;建议从 k=3 开始试,配合cross_val_score观察验证集 recall 变化
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











