sklearn的pipeline应用

Pipeline及其方法

klearn.pipeline模块可以构建复合估计器以实现数据转换和估计的流水作业。

方法分类

pipeline.FeatureUnion(transformer_list[, …])

连接多个转换器对象的结果

pipeline.Pipeline(steps[, memory, verbose])

带有最终估算器的转换管线。

pipeline.make_pipeline(*steps, **kwargs)

根据给定的估计器构造管道。

pipeline.make_union(*transformers, **kwargs)

从给定的转换器构造一个特征联合。

pipeline.make_union(*transformers, **kwargs)

从给定的转换器构造一个特征联合。

Pipeline和复合估计器

Transformer(转换器)通常与classifier(分类器)、regressor(回归器)或其他估计器组合在一起,组成复合估计器。 最常用的工具是Pipeline(管道)。 Pipeline通常与FeatureUnion(特征联合)结合使用,FeatureUnion将transformer的输出连接到复合特征空间中。 TransformedTargetRegressor处理转换目标(如:对数变换y)。 相反,管道仅转换观察到的数据(X)。

Pipeline:链接估计器

pipieline可用于将多个估算器链接为一个。 这很有用,因为在处理数据时通常会有固定的步骤顺序,例如特征选择,归一化和分类。 pipieline在这里有多种用途:

便利性和封装

可以一次对pipeline中所有估计量的参数进行网格搜索。

联合参数选择

可以一次对pipeline中所有估计量的参数进行网格搜索。

安全性

通过确保使用相同的样本来训练转换器和预测器,有助于避免将统计数据从测试集泄漏到经交叉验证训练过的模型中。
除最后一个估算器外,pipeline中的所有估算器都必须是转换器(即必须具有转换方法)。 最后的估算器可以是任何类型(转换器,分类器等)。

用法

构建

pipeline是使用(键,值)对的列表构建的,其中键是包含自定义的步骤名称的字符串,而值是估计器对象:

>>> from sklearn.pipeline import Pipeline
>>> from sklearn.svm import SVC
>>> from sklearn.decomposition import PCA
>>> estimators = [('reduce_dim', PCA()), ('clf', SVC())]
>>> pipe = Pipeline(estimators)
>>> pipe 
Pipeline(memory=None,
         steps=[('reduce_dim', PCA(copy=True,...)),
                ('clf', SVC(C=1.0,...))], verbose=False)

实用程序功能make_pipeline是构造管道的简写。 它使用可变数量的估算器并返回管道,并自动填充名称:

>>> from sklearn.pipeline import make_pipeline
>>> from sklearn.naive_bayes import MultinomialNB
>>> from sklearn.preprocessing import Binarizer
>>> make_pipeline(Binarizer(), MultinomialNB()) 
Pipeline(memory=None,
         steps=[('binarizer', Binarizer(copy=True, threshold=0.0)),
                ('multinomialnb', MultinomialNB(alpha=1.0,
                                                class_prior=None,
                                                fit_prior=True))],
         verbose=False)

访问步骤

管道的估算器以列表形式存储在steps属性中,但是可以通过索引或通过对管道建立索引(使用[idx])来访问名称:

>>> pipe.steps[0]  
('reduce_dim', PCA(copy=True, iterated_power='auto', n_components=None,
                   random_state=None, svd_solver='auto', tol=0.0,
                   whiten=False))
>>> pipe[0]  
PCA(copy=True, iterated_power='auto', n_components=None, random_state=None,
    svd_solver='auto', tol=0.0, whiten=False)
>>> pipe['reduce_dim']  
PCA(copy=True, ...)

pipeline的named_steps属性允许在交互式环境中按名称访问步骤并用制表符补齐:

>>> pipe.named_steps.reduce_dim is pipe['reduce_dim']
True

也可以使用通常用于Python序列(例如列表或字符串)的切片符号来提取子管道(尽管步长只能为1)。 这对于仅执行某些转换(或其逆转换)很方便:

>>> pipe[:1] 
Pipeline(memory=None, steps=[('reduce_dim', PCA(copy=True, ...))],...)
>>> pipe[-1:] 
Pipeline(memory=None, steps=[('clf', SVC(C=1.0, ...))],...)

嵌套参数

可以使用 __ 语法访问管道中估计器的参数:

>>> pipe.set_params(clf__C=10) 
Pipeline(memory=None,
         steps=[('reduce_dim', PCA(copy=True, iterated_power='auto',...)),
                ('clf', SVC(C=10, cache_size=200, class_weight=None,...))],
         verbose=False)

这对于进行网格搜索特别重要:

>>> from sklearn.model_selection import GridSearchCV
>>> param_grid = dict(reduce_dim__n_components=[2, 5, 10],
...                   clf__C=[0.1, 10, 100])
>>> grid_search = GridSearchCV(pipe, param_grid=param_grid)

也可以将各个步骤替换为参数,非最终步骤可以设置为“passthrough”而跳过:

>>> from sklearn.linear_model import LogisticRegression
>>> param_grid = dict(reduce_dim=['passthrough', PCA(5), PCA(10)],
...                   clf=[SVC(), LogisticRegression()],
...                   clf__C=[0.1, 10, 100])
>>> grid_search = GridSearchCV(pipe, param_grid=param_grid)

可以通过索引检索管道的估计器:

>>> pipe[0]  
PCA(copy=True, ...)

或者按名称:

>>> pipe['reduce_dim']  
PCA(copy=True, ...)

注意

在管道上调用拟合与依次在每个估计器上调用拟合、转换输入并将其传递到下一步相同。 管道具有管道中最后一个估计器具有的所有方法,即,如果最后一个估计器是分类器,则可以将管道用作分类器。 如果最后一个估计器是变换器,那么管道也是。

缓存转换器:避免重复计算

拟合变换器可能计算量巨大。 通过设置memory参数,管道将在调用fit之后缓存每个转换器。 如果参数和输入数据相同,则使用此功能可避免计算管道内的拟合转换器的计算。 一个典型的例子是在网格搜索中,其中的转换器只需拟合一次,并可以重复用于每种配置。
memory参数用来缓存转换器。 memory可以是包含要存放转换器的目录的字符串,也可以是joblib.Memory对象:

>>> from tempfile import mkdtemp
>>> from shutil import rmtree
>>> from sklearn.decomposition import PCA
>>> from sklearn.svm import SVC
>>> from sklearn.pipeline import Pipeline
>>> estimators = [('reduce_dim', PCA()), ('clf', SVC())]
>>> cachedir = mkdtemp()
>>> pipe = Pipeline(estimators, memory=cachedir)
>>> pipe 
Pipeline(...,
         steps=[('reduce_dim', PCA(copy=True,...)),
                ('clf', SVC(C=1.0,...))], verbose=False)
>>> # Clear the cache directory when you don't need it anymore不再需要时清除缓存目录
>>> rmtree(cachedir)

警告:
Side effect of caching transformers缓存转换器的副作用
Using a Pipeline without cache enabled, it is possible to inspect the original instance such as: 使用未启用缓存的管道,可以检查原始实例,例如:

>>> from sklearn.datasets import load_digits
>>> digits = load_digits()
>>> pca1 = PCA()
>>> svm1 = SVC(gamma='scale')
>>> pipe = Pipeline([('reduce_dim', pca1), ('clf', svm1)])
>>> pipe.fit(digits.data, digits.target)
... 
Pipeline(memory=None,
         steps=[('reduce_dim', PCA(...)), ('clf', SVC(...))],
         verbose=False)
>>> # The pca instance can be inspected directly可以直接检查pca实例
>>> print(pca1.components_) 
    [[-1.77484909e-19  ... 4.07058917e-18]]

启用缓存会在拟合前触发转换器的复制。 因此,不能直接检查提供给管道的转换器实例。 在以下示例中,由于pca2将是未拟合的转换器,因此访问PCA实例pca2将引发属性错误。 因此,要使用named_steps属性检查管道中的估计量:

>>> cachedir = mkdtemp()
>>> pca2 = PCA()
>>> svm2 = SVC(gamma='scale')
>>> cached_pipe = Pipeline([('reduce_dim', pca2), ('clf', svm2)],
...                        memory=cachedir)
>>> cached_pipe.fit(digits.data, digits.target)
... 
 Pipeline(memory=...,
          steps=[('reduce_dim', PCA(...)), ('clf', SVC(...))],
          verbose=False)
>>> print(cached_pipe.named_steps['reduce_dim'].components_)
... 
    [[-1.77484909e-19  ... 4.07058917e-18]]
>>> # Remove the cache directory删除缓存目录
>>> rmtree(cachedir)

回归中的转换目标

TransformedTargetRegressor在拟合回归模型之前先转换目标y。 预测通过逆变换映射回原始空间。回归器将其作为参数用于预测,此转换器将应用于目标变量:

>>> import numpy as np
>>> from sklearn.datasets import load_boston
>>> from sklearn.compose import TransformedTargetRegressor
>>> from sklearn.preprocessing import QuantileTransformer
>>> from sklearn.linear_model import LinearRegression
>>> from sklearn.model_selection import train_test_split
>>> boston = load_boston()
>>> X = boston.data
>>> y = boston.target
>>> transformer = QuantileTransformer(output_distribution='normal')
>>> regressor = LinearRegression()
>>> regr = TransformedTargetRegressor(regressor=regressor,
...                                   transformer=transformer)
>>> X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
>>> regr.fit(X_train, y_train) 
TransformedTargetRegressor(...)
>>> print('R2 score: {0:.2f}'.format(regr.score(X_test, y_test)))
R2 score: 0.67
>>> raw_target_regr = LinearRegression().fit(X_train, y_train)
>>> print('R2 score: {0:.2f}'.format(raw_target_regr.score(X_test, y_test)))
R2 score: 0.64

对于简单的转换,可以传递一对函数来定义转换及其逆映射,而不是Transformer对象:

>>> def func(x):
...     return np.log(x)
>>> def inverse_func(x):
...     return np.exp(x)

随后,对象创建为:

>>> regr = TransformedTargetRegressor(regressor=regressor,
...                                   func=func,
...                                   inverse_func=inverse_func)
>>> regr.fit(X_train, y_train) 
TransformedTargetRegressor(...)
>>> print('R2 score: {0:.2f}'.format(regr.score(X_test, y_test)))
R2 score: 0.65

默认情况下,所提供的函数在每次拟合时都要检查是否彼此为逆。 但是,可以通过将check_inverse设置为False来绕过此检查:

>>> def inverse_func(x):
...     return x
>>> regr = TransformedTargetRegressor(regressor=regressor,
...                                   func=func,
...                                   inverse_func=inverse_func,
...                                   check_inverse=False)
>>> regr.fit(X_train, y_train) 
TransformedTargetRegressor(...)
>>> print('R2 score: {0:.2f}'.format(regr.score(X_test, y_test)))
R2 score: -4.50

注意:
可以通过设置转换器或函数对func和inverse_func来触发转换。 但是,同时设置这两个选项将引发错误。

特征融合

FeatureUnion将多个转换器对象合并到一个新的转换器中,该转换器将其输出合并在一起。 FeatureUnion包含一个转换器对象列表。 在拟合期间,每个参数都独立地适合数据。 并行应用这些转换器,并将它们输出的特征矩阵并排连接成一个更大的矩阵。
如果要对数据的每个字段应用不同的转换,可参阅相关的类sklearn.compose.ColumnTransformer(见此文后半部分)
FeatureUnion与管道具有相同的特性-便利性以及联合参数估计和验证。
FeatureUnion和Pipeline可以组合以创建复杂的模型。
(FeatureUnion无法检查两个转换器是否可能产生相同的特征。它仅在特征集不相交时才融合,所以调用时要注意。)

用法

FeatureUnion是使用(键,值)对的列表构建的,其中键是要为给定转换指定的名称(任意字符串;它仅用作标识符),而value是估计对象:

>>> from sklearn.pipeline import FeatureUnion
>>> from sklearn.decomposition import PCA
>>> from sklearn.decomposition import KernelPCA
>>> estimators = [('linear_pca', PCA()), ('kernel_pca', KernelPCA())]
>>> combined = FeatureUnion(estimators)
>>> combined 
FeatureUnion(n_jobs=None,
             transformer_list=[('linear_pca', PCA(copy=True,...)),
                               ('kernel_pca', KernelPCA(alpha=1.0,...))],
             transformer_weights=None, verbose=False)

像管道一样,特征融合具有一个名为make_union的简化构造函数,该构造函数不需要显式命名组件。
与管道类似,可以使用set_params替换各个步骤,并通过将其设置为’drop’来忽略它们:

>>> combined.set_params(kernel_pca='drop')
... 
FeatureUnion(n_jobs=None,
             transformer_list=[('linear_pca', PCA(copy=True,...)),
                               ('kernel_pca', 'drop')],
             transformer_weights=None, verbose=False)

用于异构数据的ColumnTransformer

注意:
compose.ColumnTransformer类是实验性的,API可能会发生变化。
许多数据集包含不同类型的要素,例如文本,浮点数和日期,其中每种类型的要素都需要单独的预处理或要素提取步骤。通常,在应用scikit-learn方法之前,例如使用pandas,对数据进行预处理最容易。由于以下原因之一,在将数据传递给scikit-learn之前进行处理可能会出现问题:
1.将来自测试数据的统计信息合并到预处理器中,会使交叉验证得分不可靠(称为数据泄漏),例如在定标器或估算缺失值的情况下。
2.你可能希望在参数搜索中包括预处理器的参数。
ColumnTransformer有助于在管道内对数据的不同列执行不同的转换,以防止数据泄漏并且可以对其进行参数化。 ColumnTransformer可处理数组,稀疏矩阵和pandas DataFrame。
可以对每列应用不同的转换,例如预处理或特定的特征提取方法:

>>> import pandas as pd
>>> X = pd.DataFrame(
...     {'city': ['London', 'London', 'Paris', 'Sallisaw'],
...      'title': ["His Last Bow", "How Watson Learned the Trick",
...                "A Moveable Feast", "The Grapes of Wrath"],
...      'expert_rating': [5, 3, 4, 5],
...      'user_rating': [4, 5, 4, 3]})

对于此数据,我们可能希望使用preprocessing.OneHotEncoder将“ city”列编码为类别变量,但将一个feature_extraction.text.CountVectorizer应用于“ title”列。 由于我们可能在同一列上使用多种特征提取方法,因此我们给每个转换器一个唯一的名称,例如“ city_category”和“ title_bow”。 默认情况下,其余列将被忽略(remainder =‘drop’):

>>> from sklearn.compose import ColumnTransformer
>>> from sklearn.feature_extraction.text import CountVectorizer
>>> from sklearn.preprocessing import OneHotEncoder
>>> column_trans = ColumnTransformer(
...     [('city_category', OneHotEncoder(dtype='int'),['city']),
...      ('title_bow', CountVectorizer(), 'title')],
...     remainder='drop')

>>> column_trans.fit(X) 
ColumnTransformer(n_jobs=None, remainder='drop', sparse_threshold=0.3,
    transformer_weights=None,
    transformers=...)

>>> column_trans.get_feature_names()
... 
['city_category__x0_London', 'city_category__x0_Paris', 'city_category__x0_Sallisaw',
'title_bow__bow', 'title_bow__feast', 'title_bow__grapes', 'title_bow__his',
'title_bow__how', 'title_bow__last', 'title_bow__learned', 'title_bow__moveable',
'title_bow__of', 'title_bow__the', 'title_bow__trick', 'title_bow__watson',
'title_bow__wrath']

>>> column_trans.transform(X).toarray()
... 
array([[1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0],
       [1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0],
       [0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
       [0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1]]...)

在上面的示例中,CountVectorizer希望将一维数组作为输入,因此将列指定为字符串(‘title’)。 但是,与其他大多数转换器一样,preprocessing.OneHotEncoder需要2D数据,因此,在这种情况下,需要将列指定为字符串列表([‘city’])。
除了标量或单个项目列表之外,可以将列选择指定为多个项目,整数数组,切片或布尔掩码的列表。 如果输入是DataFrame,则字符串可以引用列,整数始终被解释为位置列。
可以通过设置restder ='passthrough’来保留剩余列。 这些值将附加到转换的末尾:

>>> column_trans = ColumnTransformer(
...     [('city_category', OneHotEncoder(dtype='int'),['city']),
...      ('title_bow', CountVectorizer(), 'title')],
...     remainder='passthrough')

>>> column_trans.fit_transform(X)
... 
array([[1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 5, 4],
       [1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 3, 5],
       [0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 4],
       [0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 5, 3]]...)

可以将remainder参数设置为估算器,以转换剩余的列。 转换后的值将附加到转换的末尾:

>>> from sklearn.preprocessing import MinMaxScaler
>>> column_trans = ColumnTransformer(
...     [('city_category', OneHotEncoder(), ['city']),
...      ('title_bow', CountVectorizer(), 'title')],
...     remainder=MinMaxScaler())

>>> column_trans.fit_transform(X)[:, -2:]
... 
array([[1. , 0.5],
       [0. , 1. ],
       [0.5, 0.5],
       [1. , 0. ]])

make_column_transformer函数可用于更轻松地创建ColumnTransformer对象。 具体来说,名称将自动给出。 以上示例的等效项为:

>>> from sklearn.compose import make_column_transformer
>>> column_trans = make_column_transformer(
...     (OneHotEncoder(), ['city']),
...     (CountVectorizer(), 'title'),
...     remainder=MinMaxScaler())
>>> column_trans 
ColumnTransformer(n_jobs=None, remainder=MinMaxScaler(copy=True, ...),
         sparse_threshold=0.3,
         transformer_weights=None,
         transformers=[('onehotencoder', ...)

饮马江湖,仗剑天涯,希望能对你有帮助,有喜欢的同道中人,打个赏呗^_^

你可能感兴趣的:(Python,机器学习,算法)