无法将组合的 SMOTE 和 RandomUnderSampler 管道送入主管道

Not able to feed the combined SMOTE & RandomUnderSampler pipeline into the main pipeline

我目前正在使用不平衡数据集,为了处理不平衡,我计划将 SMOTE 和 ADASYN 与 RandomUnderSampler 结合使用,以及单独的欠采样、过采样、SMOTE 和 ADASYN(总共 6 种采样方式,我将作为 GridSearchCV 中的参数传递)。我为此创建了两个管道。

Smote_Under_pipeline = imb_Pipeline([
     ('smote', SMOTE(random_state=rnd_state, n_jobs=-1)),
     ('under', RandomUnderSampler(random_state=rnd_state)),
])

Adasyn_Under_pipeline = imb_Pipeline([
     ('adasyn', ADASYN(random_state=rnd_state, n_jobs=-1)),
     ('under', RandomUnderSampler(random_state=rnd_state)), 
])

我的计划是将这两个pipleines送入主pipeline,是这样的:

Main_Pipeline = imb_Pipeline([
     ('feature_handler', FeatureTransformer(list(pearson_feature_vector.index))),
     ('imb', Smote_Under_pipeline),
     ('scaler', StandardScaler()),
     ('pca', PCA(n_components=0.99)),
     ('model', LogisticRegression(max_iter=1750)),
])

FeatureTransformer() 是一个特征选择器 class:

class FeatureTransformer(BaseEstimator, TransformerMixin):

    def __init__(self, feature_vector=None):
        self.feature_vector = feature_vector
    
    def fit(self, X, y):
        return self

    def transform(self, X):
        return X[self.feature_vector]

当我调用 Smote_Under_pipeline.fit()Adasyn_Under_pipeline.fit() 时,它起作用了(下面的示例代码):

dumm_x, dumm_y = Smote_Under_pipeline.fit_resample(X_train, y_train)

但是当我尝试初始化 Main_Pipeline 时解释器抛出一个错误:

TypeError: All intermediate steps of the chain should be estimators that implement fit and transform or fit_resample. 'Pipeline(steps=[('smote', SMOTE(n_jobs=-1, random_state=42)),
            ('under', RandomUnderSampler(random_state=42))])' implements both)

我正在使用 Imbalance-learn 提供的管道。

我无法理解错误。在使用 scikit-learn 管道时,所有中间估计器都有自己的 fit() & fit_transform() 方法,imblearn 管道给出处理 fit_resample() 方法的附加功能,它由以下两者公开:Smote_Under_pipeline & Adasyn_Under_pipeline。所以,可以在Main_Pipeline中调用,那为什么会报错呢?两个采样管道都公开了 fit() 方法以及 fit_resample(),这是原因吗?

为了强调@glemaitre 的评论,是管道(内部管道)同时具有转换和重采样导致了问题。

所以扁平化管道(包括直接在主管道中的重采样器)似乎是解决方案。您可以通过关闭各个步骤来测试不同的重采样策略作为超参数:

Main_Pipeline = imb_Pipeline([
     ('feature_handler', FeatureTransformer(list(pearson_feature_vector.index))),
     ('oversamp', None),
     ('undersamp', None),
     ('scaler', StandardScaler()),
     ('pca', PCA(n_components=0.99)),
     ('model', LogisticRegression(max_iter=1750)),
])

param_space = {
    'oversamp': [None, SMOTE(...), ADASYN(...), RandomOverSampler(...)],
    'undersamp': [None, RandomUnderSampler(...)],
    ...,
}

这将提供 8 种组合,除了您想要的组合之外,还包括 None-None 和过度欠采样。但这对我来说似乎没问题:与无重采样管道进行比较会很好,并且过欠采样类似于合成欠采样组合。