【问题标题】:Does imblearn pipeline turn off sampling for testing?imblearn 管道是否会关闭采样以进行测试?
【发布时间】:2020-12-10 17:23:59
【问题描述】:

让我们假设以下代码(来自imblearn example on pipelines

...    
# Instanciate a PCA object for the sake of easy visualisation
pca = PCA(n_components=2)

# Create the samplers
enn = EditedNearestNeighbours()
renn = RepeatedEditedNearestNeighbours()

# Create the classifier
knn = KNN(1)

# Make the splits
X_train, X_test, y_train, y_test = tts(X, y, random_state=42)

# Add one transformers and two samplers in the pipeline object
pipeline = make_pipeline(pca, enn, renn, knn)

pipeline.fit(X_train, y_train)
y_hat = pipeline.predict(X_test)

我想确保在执行pipeline.predict(X_test) 时不会执行采样程序ennrenn(但当然必须执行pca)。

  1. 首先,我很清楚over-, under-, and mixed-sampling 是 程序适用于training set,而不是 test/validation set。如果我错了,请在这里纠正我。

  2. 我浏览了imblearn Pipeline 代码,但找不到 predict 方法在那里。

  3. 我还想确保这种正确的行为在以下情况下有效 管道位于GridSearchCV

我只需要确保imblearn.Pipeline 会发生这种情况。

编辑:2020-08-28

@wundermahn 回答就是我所需要的。

此编辑只是为了补充一点,这是应该使用imblearn.Pipeline 进行不平衡预处理而不是sklearn.Pipelineimblearn 文档中的任何地方我找到了解释为什么需要imblearn.Pipeline 的原因有sklearn.Pipeline

【问题讨论】:

  • 嗨@JacquesWainer,如果这回答了您的问题,请接受:) 如果没有,请告诉我您还希望我补充什么。

标签: python machine-learning imblearn


【解决方案1】:

好问题。按照您发布的顺序浏览它们:

  1. 首先,我很清楚,过采样、欠采样和混合采样是应用于训练集的过程,而不是应用于 测试/验证集。如果我错了,请在这里纠正我。

没错。您当然不想测试(无论是在您的 test 还是 validation 数据上)代表实际、实时、“生产”数据集的数据。你真的应该只将此应用于培训。请注意,如果您使用交叉折叠验证等技术,则应将抽样分别应用于每个折叠,如 this IEEE paper 所示。

  1. 我浏览了 imblearn Pipeline 代码,但在那里找不到 predict 方法。

我假设你找到了 imblearn.pipeline source code,所以如果你找到了,你想做的就是看看 fit_predict 方法:

 @if_delegate_has_method(delegate="_final_estimator")
    def fit_predict(self, X, y=None, **fit_params):
        """Apply `fit_predict` of last step in pipeline after transforms.
        Applies fit_transforms of a pipeline to the data, followed by the
        fit_predict method of the final estimator in the pipeline. Valid
        only if the final estimator implements fit_predict.
        Parameters
        ----------
        X : iterable
            Training data. Must fulfill input requirements of first step of
            the pipeline.
        y : iterable, default=None
            Training targets. Must fulfill label requirements for all steps
            of the pipeline.
        **fit_params : dict of string -> object
            Parameters passed to the ``fit`` method of each step, where
            each parameter name is prefixed such that parameter ``p`` for step
            ``s`` has key ``s__p``.
        Returns
        -------
        y_pred : ndarray of shape (n_samples,)
            The predicted target.
        """
        Xt, yt, fit_params = self._fit(X, y, **fit_params)
        with _print_elapsed_time('Pipeline',
                                 self._log_message(len(self.steps) - 1)):
            y_pred = self.steps[-1][-1].fit_predict(Xt, yt, **fit_params)
        return y_pred

在这里,我们可以看到pipeline利用了管道中最终估计器的.predict方法,在您发布的示例中,scikit-learn's knn

 def predict(self, X):
        """Predict the class labels for the provided data.
        Parameters
        ----------
        X : array-like of shape (n_queries, n_features), \
                or (n_queries, n_indexed) if metric == 'precomputed'
            Test samples.
        Returns
        -------
        y : ndarray of shape (n_queries,) or (n_queries, n_outputs)
            Class labels for each data sample.
        """
        X = check_array(X, accept_sparse='csr')

        neigh_dist, neigh_ind = self.kneighbors(X)
        classes_ = self.classes_
        _y = self._y
        if not self.outputs_2d_:
            _y = self._y.reshape((-1, 1))
            classes_ = [self.classes_]

        n_outputs = len(classes_)
        n_queries = _num_samples(X)
        weights = _get_weights(neigh_dist, self.weights)

        y_pred = np.empty((n_queries, n_outputs), dtype=classes_[0].dtype)
        for k, classes_k in enumerate(classes_):
            if weights is None:
                mode, _ = stats.mode(_y[neigh_ind, k], axis=1)
            else:
                mode, _ = weighted_mode(_y[neigh_ind, k], weights, axis=1)

            mode = np.asarray(mode.ravel(), dtype=np.intp)
            y_pred[:, k] = classes_k.take(mode)

        if not self.outputs_2d_:
            y_pred = y_pred.ravel()

        return y_pred
  1. 我还想确保当管道位于 GridSearchCV 内时,这种正确的行为是否有效

这种假设以上两个假设是正确的,我认为这意味着您想要在 GridSearchCV 中工作的 complete, minimal, reproducible examplescikit-learn on this 提供了大量文档,但我使用 knn 创建的示例如下:

import pandas as pd, numpy as np

from imblearn.over_sampling import SMOTE
from imblearn.pipeline import Pipeline
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_digits
from sklearn.model_selection import GridSearchCV, train_test_split

param_grid = [
    {
        'classification__n_neighbors': [1,3,5,7,10],
    }
]

X, y = load_digits(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, test_size=0.20)

pipe = Pipeline([
    ('sampling', SMOTE()),
    ('classification', KNeighborsClassifier())
])

grid = GridSearchCV(pipe, param_grid=param_grid)
grid.fit(X_train, y_train)
mean_scores = np.array(grid.cv_results_['mean_test_score'])
print(mean_scores)

# [0.98051926 0.98121129 0.97981998 0.98050474 0.97494193]

你的直觉是正确的,干得好:)

【讨论】:

  • 只是为了澄清一下,如果我要使用欠采样器,训练集将欠采样,但测试集将包含与我欠采样之前相同比例的不平衡?
  • @mathella 您可以“采样”您想要的任何数据集。抽样只是添加或删除数据的一种统计方式。但是,您应该让您的测试集保持最能反映您的模型在现场看到的不平衡状态。因此,假设您以分层方式拆分训练数据和测试数据,并且两者都代表您的生产数据,那么是的,您的训练数据将被抽样,而您的测试数据不会被抽样。
猜你喜欢
  • 2022-09-26
  • 2019-09-24
  • 2018-01-13
  • 2021-02-09
  • 2020-03-07
  • 2020-09-19
  • 2018-08-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多