Press "Enter" to skip to content

《SciKit Pipelines 简介》

为什么你应该开始使用它们。

Sigmund在Unsplash上的照片

你是否曾经训练过一个机器学习模型,而你的预测结果看起来太好以至于难以置信?但是后来你意识到你的训练数据和测试数据之间存在一些数据泄漏?

或者你是否经历了许多预处理步骤来准备数据,以至于将预处理步骤从模型训练转移到生产环境中进行实际预测变得困难?

或者你的预处理变得混乱不堪,很难以可读和易于理解的方式共享你的代码?

那么你可能想要尝试一下`scikit-learn`的Pipeline。Pipeline是一个优雅的解决方案,用于设置机器学习训练、测试和生产的工作流程,使你的生活更轻松,结果更易复现。

但是什么是Pipeline,有什么好处,以及如何设置Pipeline?我将回答这些问题,并给出一些构建块的代码示例。通过组合这些构建块,你可以构建更复杂的、适合你需求的Pipeline。

什么是Pipeline?

Pipeline允许你在ML工作流中组装多个步骤,这些步骤在将数据传递给估计器之前按顺序转换数据。因此,Pipeline可以由预处理、特征工程和特征选择步骤组成,然后将数据传递给最终的分类或回归任务估计器。

为什么应该使用Pipeline?

通常情况下,使用Pipeline可以使你的生活更轻松,加快ML模型的开发速度。这是因为Pipeline具有以下优势:

  • 使代码更清晰、更易理解
  • 易于复制和理解数据工作流程
  • 更易于阅读和调整
  • 使数据准备更快,因为Pipeline自动化了数据准备过程
  • 帮助避免数据泄漏
  • 允许同时对Pipeline中的所有估计器和参数运行超参数优化
  • 方便,只需要一次调用`fit()`和`predict()`就可以运行整个数据Pipeline

在训练和优化模型,并对结果感到满意之后,你可以轻松保存训练好的Pipeline。然后,每当你想要运行模型时,只需加载预训练的Pipeline,你就可以进行一些推理工作。通过这种方式,你可以以非常清晰的方式共享你的模型,易于复制和理解。

如何设置Pipeline?

使用`scikit-learn`设置Pipeline非常简单直接。

`scikit-learn`的`Pipeline`使用一个包含要在数据上应用的变换器的键值对列表作为值。键可以任意选择。键可以用于访问变换器的参数,例如在超参数优化的网格搜索过程中运行。由于变换器存储在列表中,您还可以通过索引访问变换器。

要在Pipeline上拟合数据并进行预测,您可以像使用`scikit-learn`中的任何变换器或回归器一样运行`fit()`和`predict()`。

一个非常简单的Pipeline可能看起来像这样:

from sklearn.impute import SimpleImputerfrom sklearn.pipeline import Pipelinefrom sklearn.preprocessing import MinMaxScalerfrom sklearn.linear_model import LinearRegressionpipeline = Pipeline(   steps=[("imputer", SimpleImputer()),           ("scaler", MinMaxScaler()),           ("regression", LinearRegression())   ])pipeline.fit(X_train, y_train)y_pred = pipeline.predict(X_test)

然而,如果您不想为变换器输入键值,`scikit-learn`还可以进一步简化您的操作。相反,您可以只使用`make_pipeline()`函数,`scikit-learn`会根据变换器的类名设置名称。

from sklearn.impute import SimpleImputerfrom sklearn.pipeline import make_pipelinefrom sklearn.preprocessing import MinMaxScalerfrom sklearn.linear_model import LinearRegressionpipeline = make_pipeline(steps=[    SimpleImputer(),     MinMaxScaler(),     LinearRegression()    ])

就是这样。通过这个,您快速设置了一个简单的流水线,可以用来训练模型和进行预测。如果您想查看流水线的样子,只需打印流水线,scikit-learn会显示一个交互式视图。

但是,如果您想构建更复杂和可定制的内容怎么办?例如,处理分类和数值特征的方式不同,添加特征或转换目标值。

不用担心,scikit-learn提供了额外的功能,您可以使用这些功能创建更多定制的流水线,并将您的流水线提升到一个新的水平。这些函数包括:

  • ColumnTransformer
  • FeatureUnion
  • TransformedTargetRegressor

我将逐个介绍它们,并向您展示如何使用它们的示例。

转换选择的特征

如果您有不同类型的特征,例如连续和分类特征,您可能希望以不同的方式转换这些特征。例如,在缩放连续特征的同时进行独热编码分类特征。

您可以在将特征传入流水线之前进行这些预处理步骤。但是这样做会导致您无法在后续的超参数搜索中包含这些预处理步骤和参数。而且,将它们包含在流水线中可以更轻松地处理您的机器学习模型。

要仅对选定的列应用转换或甚至一系列转换,您可以使用ColumnTransformer。使用方法与Pipeline非常相似,只需将键值对传递给transformers,而不是传递给steps。然后,我们可以将创建的转换器作为流水线中的一步包含进去。

from sklearn.compose import ColumnTransformerfrom sklearn.pipeline import Pipelinefrom sklearn.preprocessing import OneHotEncodercategorical_transformer = ColumnTransformer( transformers=[("encode", OneHotEncoder())])pipeline = Pipeline(steps=[ ("categorical", categorical_transformer, ["col_name"]) ])

由于我们只想在特定的列上运行转换,我们需要将这些列传递给流水线。此外,我们还可以让ColumnTransformer知道我们想要对剩余的列做什么。例如,如果您想保留转换器未改变的列,需要将remainder设置为passthrough。否则,这些列将被删除。除了不进行任何操作或删除列,您还可以通过传递转换器来转换剩余的列。

from sklearn.compose import ColumnTransformerfrom sklearn.preprocessing import MinMaxScaler, OneHotEncodercategorical_transformer = ColumnTransformer( transformers=[("encode", OneHotEncoder(), ["col_name"])], remainder="passthrough")categorical_transformer = ColumnTransformer( transformers=[("encode", OneHotEncoder(), ["col_name"])], remainder=MinMaxScaler())```

由于scikit-learn允许堆叠Pipeline,我们甚至可以将一个Pipeline传递给ColumnTransformer,而不是在ColumnTransformer中声明我们想要进行的每个转换。

from sklearn.compose import ColumnTransformerfrom sklearn.impute import SimpleImputerfrom sklearn.pipeline import Pipelinefrom sklearn.preprocessing import MinMaxScaler, OneHotEncodercategorical_transformer = Pipeline(steps=[("encode", OneHotEncoder())])numerical_transformer = Pipeline( steps=[("imputation", SimpleImputer()), ("scaling", MinMaxScaler())])preprocessor = ColumnTransformer( transfomers=[ ("numeric", numerical_transformer), ("categoric", categorical_transformer, ["col_name"]), ])pipeline = Pipeline(steps=["preprocesssing", preprocessor])

合并特征

现在,您可以在不同的列上运行不同的预处理步骤,但是如果您想从数据中提取新特征并将它们添加到您的特征集中,该怎么办?

为此,您可以使用FeatureUnion,它将转换器对象组合成一个新的转换器,并将每个转换器的输出连接起来。

例如,假设我们想将移动平均作为一个特征添加进来,我们可以这样做:

from sklearn.compose import FeatureUnionfrom sklearn.pipeline import Pipelinepreprocessor = ( FeatureUnion( [ ("moving_Average", MovingAverage(window=30)), ("numerical", numerical_pipeline), ] ),)pipeline = Pipeline(steps=["preprocesssing", preprocessor])

转换目标值

如果你有一个回归问题,有时在拟合回归模型之前,将目标值进行转换可以有所帮助。

你可以使用TransformedTargetRegressor类来包含这样的转换。使用这个类,你可以使用scikit-learn提供的转换器,比如MinMax缩放器,或者编写自己的转换函数。

TransformedTargetRegressor的一个巨大优势是它通过逆转换自动将预测映射回原始空间。因此,当你从模型训练转向在生产环境中进行预测时,你无需担心这个问题。

from sklearn.compose import TransformedTargetRegressorfrom sklearn.impute import SimpleImputerfrom sklearn.pipeline import Pipelinefrom sklearn.preprocessing import MinMaxScalerregressor = TransformedTargetRegressor(    regressor=model,     func=np.log1p,     inverse_func=np.expm1)pipeline = Pipeline(   steps=[      ("imputer", SimpleImputer()),       ("scaler", MinMaxScaler()),       ("regressor", regressor)    ])pipeline.fit(X_train, y_train)y_pred = pipeline.predict(X_test)

构建自定义函数

有时使用scikit-learn提供的预处理方法是不够的。然而,在使用流水线时,这并不会阻碍你。你可以轻松地创建自己的函数,然后将其包含在流水线中。

为此,你需要构建一个包含fit()transform()方法的类,因为这些方法在运行流水线时被调用。然而,这些方法不一定需要执行任何操作。此外,我们可以让该类继承scikit-learnBaseEstimatorTransformerMixin类,以提供流水线所需的一些基本功能。

例如,假设我们想对时间序列进行预测,并希望通过移动平均平滑所有特征。为此,我们只需设置一个包含平滑部分的transform方法的类。

from sklearn.base import BaseEstimator, TransformerMixinfrom sklearn.impute import SimpleImputerfrom sklearn.pipeline import Pipelinefrom sklearn.preprocessing import MinMaxScalerclass MovingAverage(BaseEstimator, TransformerMixin):    def __init__(self, window=30):          self.window = window        def fit(self, X, y=None):          return self        def transform(self, X, y=None):        return X.rolling(window=self.window, min_periods=1, center=False).mean()pipeline = Pipeline(   steps=[       ("ma", MovingAverage(window=30)),       ("imputer", SimpleImputer()),       ("scaler", MinMaxScaler()),       ("regressor", model),   ])pipeline.fit(X_train, y_train)y_pred = pipeline.predict(X_test)

还有什么需要知道的吗?

scikit-learn中转换器的默认返回是一个numpy数组。如果你只想在流水线的第二个步骤中对某些特征应用转换(例如,只对分类特征应用转换),这可能会导致流水线出现问题。

然而,为了防止流水线出现问题,你可以将所有转换器的默认返回值更改为DataFrame,方法是:

from sklearn import set_configset_config(transform_output = "pandas")

在运行超参数优化或检查流水线的单个参数时,直接访问参数可能会很有帮助。你可以使用<estimator>__<parameter>语法来访问参数。例如,在上面的移动平均示例中,我们可以通过调用pipeline.set_params(pipeline__ma_window=7)来访问MovingAverage转换器的窗口宽度。

结论

使用scikit-learn的流水线可以在开发新的机器学习模型和设置预处理步骤时简化你的工作。除了具有许多好处外,设置流水线也是简单而直观的。然而,你可以构建复杂且可自定义的预处理流水线,在其中只有你的创造力限制了边界。

如果你喜欢这篇文章或有任何问题,请随时留下评论或与我联系。我也对你在使用scikit-learn的流水线方面的经验感兴趣。

你想要了解有关Pipelines的更多信息吗?请点击以下链接:

  • https://scikit-learn.org/stable/modules/compose.html#pipeline
Leave a Reply

Your email address will not be published. Required fields are marked *