klearn.pipeline模块可以构建复合估计器以实现数据转换和估计的流水作业。
连接多个转换器对象的结果
带有最终估算器的转换管线。
根据给定的估计器构造管道。
从给定的转换器构造一个特征联合。
从给定的转换器构造一个特征联合。
Transformer(转换器)通常与classifier(分类器)、regressor(回归器)或其他估计器组合在一起,组成复合估计器。 最常用的工具是Pipeline(管道)。 Pipeline通常与FeatureUnion(特征联合)结合使用,FeatureUnion将transformer的输出连接到复合特征空间中。 TransformedTargetRegressor处理转换目标(如:对数变换y)。 相反,管道仅转换观察到的数据(X)。
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)
注意:
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', ...)
饮马江湖,仗剑天涯,希望能对你有帮助,有喜欢的同道中人,打个赏呗^_^