下采样前必须检查类别分布,否则可能删掉关键样本;需用Counter查看标签分布,少数类样本≤10时禁用下采样;RandomUnderSampler须设random_state=42且仅作用于训练集;ENN慎用,需标准化并调小k;下采样后须重跑交叉验证或封装进ImbPipeline。

下采样前必须检查类别分布,否则可能删掉关键样本
直接调用 RandomUnderSampler 很容易,但盲目下采样会让少数类进一步失真,尤其当少数类本身样本就极少(比如只有 5–10 个)时,下采样后训练集可能只剩 2–3 个样本,模型根本学不到判别模式。务必先用 value_counts() 或 collections.Counter 查看原始标签分布:
from collections import Counter
print(Counter(y_train)) # 输出类似 Counter({0: 982, 1: 18})如果少数类样本数 10:1),再考虑下采样作为预处理环节之一。
用 RandomUnderSampler 时要设 random_state 并避开验证集
RandomUnderSampler 默认随机丢弃多数类样本,不设 random_state 会导致每次运行结果不同,无法复现、也难调试。更重要的是:下采样只能作用于训练集,绝不能对整个数据集(含测试集)操作——否则会泄露标签分布信息,导致评估虚高。
- 正确做法:只在划分后的
X_train,y_train上拟合和变换 - 错误写法:
rus.fit_resample(X, y)(X 和 y 包含测试样本) - 必须加
random_state=42保证可复现
from imblearn.under_sampling import RandomUnderSampler rus = RandomUnderSampler(random_state=42) X_train_rus, y_train_rus = rus.fit_resample(X_train, y_train)
慎用 EditedNearestNeighbours:它可能误删边界样本
相比纯随机下采样,EditedNearestNeighbours(ENN)会删除那些与其近邻类别不一致的多数类样本,理论上能保留决策边界附近的“有用”样本。但它依赖 k 近邻距离计算,在高维稀疏特征或噪声较多时容易把本该保留的边界点当成噪声删掉,反而削弱模型区分能力。
立即学习“Python免费学习笔记(深入)”;
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- k 默认为 3,高维数据建议调小(如 k=1)或改用
RepeatedEditedNearestNeighbours - ENN 对标准化敏感,务必在下采样前对特征做
StandardScaler或MinMaxScaler - 执行后检查
y_train_rus的分布,确认没意外清空某个子类
下采样后必须重跑交叉验证,不能复用原始 CV 划分
原始的 StratifiedKFold 划分是基于未下采样的 y_train,一旦你用 fit_resample 改变了训练集大小和标签分布,原来的 fold 划分就失效了。直接套用会导致某几个 fold 中少数类样本为 0,F1 或 roc_auc 计算崩溃(报 UndefinedMetricWarning 或 ValueError: Only one class present in y_true)。
正确流程是:把下采样封装进 Pipeline,或每次 CV fold 内独立做下采样:
from sklearn.pipeline import Pipeline
from imblearn.pipeline import Pipeline as ImbPipeline # 注意用 imblearn 的 Pipeline
pipe = ImbPipeline([
('rus', RandomUnderSampler(random_state=42)),
('clf', LogisticRegression())
])
# 然后用 cross_val_score(pipe, X_train, y_train, scoring='f1')单独用 scikit-learn 的 Pipeline 会报错,因为普通 Pipeline 不支持 resampler 的 fit_resample 接口。
下采样不是万能解药,尤其当原始少数类本身就高度重叠或特征区分度低时,强行平衡反而让模型更难学到真实差异。动手前先画个 t-SNE 或 PCA 图看看类间可分性,比急着调 RandomUnderSampler 更有效。

















