Sklearn/imblearn管道交叉验证:是否仅重采样训练集,验证集保持不平衡?
不平衡数据集K折交叉验证+SMOTE重采样的实现说明
imblearn的Pipeline完全可以实现你的需求,且只会在交叉验证的训练折上执行SMOTE重采样,验证折将保持原始的不平衡状态。
核心机制说明
Sklearn(包括imblearn扩展)的交叉验证逻辑严格遵循"训练集单独处理"的原则:
- 在每一折交叉验证中,先将数据集划分为训练折和验证折
- 管道中的所有预处理/重采样步骤(比如SMOTE)仅会对训练折执行拟合和转换操作
- 验证折始终保持原始的不平衡状态,仅用于模型评估,不会被任何重采样操作修改
这样做的目的是避免数据泄露——在真实场景中,你无法对未见过的测试数据做重采样,因此交叉验证必须模拟这种情况,才能得到真实可信的模型评估结果。
代码示例
以下是完整的实现代码,包含数据集生成、管道构建、交叉验证及验证集分布验证:
# 导入依赖库 import numpy as np from sklearn.datasets import make_classification from sklearn.model_selection import cross_val_score, KFold from sklearn.svm import SVC from imblearn.pipeline import Pipeline from imblearn.over_sampling import SMOTE # 生成不平衡数据集(类别0占90%,类别1占10%) X, y = make_classification( n_samples=1000, n_features=10, n_informative=2, n_redundant=0, n_clusters_per_class=1, weights=[0.9], random_state=42 ) # 构建imblearn管道:先SMOTE重采样,再训练SVM分类器 pipe = Pipeline([ ('smote', SMOTE(random_state=42)), ('classifier', SVC()) ]) # 定义5折交叉验证(开启洗牌保证数据分布均匀) kf = KFold(n_splits=5, shuffle=True, random_state=42) # 执行交叉验证,计算平均准确率 scores = cross_val_score(pipe, X, y, cv=kf, scoring='accuracy') print(f"5折交叉验证平均准确率: {scores.mean():.4f} ± {scores.std():.4f}") # 验证每一折中验证集的原始不平衡状态 for fold_num, (train_idx, val_idx) in enumerate(kf.split(X), 1): val_class_counts = np.bincount(y[val_idx]) print(f"\n第{fold_num}折验证集类别分布:") print(f"类别0: {val_class_counts[0]}个,类别1: {val_class_counts[1]}个") print(f"类别比例: {val_class_counts[0]/val_class_counts[1]:.2f}:1")
关键细节解释
- 管道中的
SMOTE组件仅在fit阶段对训练集执行重采样,transform阶段不会修改输入数据(直接返回原数据) cross_val_score在每一折中会自动拆分数据,对训练子集调用pipe.fit(),对验证子集仅调用pipe.predict(),因此验证集不会被SMOTE处理- 运行代码后可看到,每一折验证集的类别比例始终接近9:1,和原始数据集一致,证明验证集未被重采样
内容的提问来源于stack exchange,提问作者displayname
相关产品推荐
相关产品推荐

