38.md 22.0 KB
Newer Older
L
loopyme 已提交
1
# 5.1. Pipeline(管道)和 FeatureUnion(特征联合): 合并的评估器
W
init  
wizardforcel 已提交
2 3 4

校验者:
        [@程威](https://github.com/apachecn/scikit-learn-doc-zh)
L
loopyme 已提交
5
        [@Loopy](https://github.com/loopyme)
W
init  
wizardforcel 已提交
6 7 8
翻译者:
        [@Sehriff](https://github.com/apachecn/scikit-learn-doc-zh)

L
loopyme 已提交
9
变换器(Transformers)通常与分类器,回归器或其他的学习器组合在一起以构建复合估计器。 完成这件事的最常用工具是 [Pipeline](#511-pipeline-链式评估器)。 Pipeline 经常与 FeatureUnion 结合起来使用。 FeatureUnion 用于将变换器(transformers)的输出串联到复合特征空间(composite feature space)中。 TransformedTargetRegressor 用来处理变换 target (即对数变化 y)。 作为对比,Pipelines类只用来变换(transform)观测数据(X)。
W
init  
wizardforcel 已提交
10

L
loopyme 已提交
11
## 5.1.1. Pipeline: 链式评估器
W
init  
wizardforcel 已提交
12

V
VPrincekin 已提交
13
 [`Pipeline`](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html#sklearn.pipeline.Pipeline "sklearn.pipeline.Pipeline") 可以把多个评估器链接成一个。这个是很有用的,因为处理数据的步骤一般都是固定的,例如特征选择、标准化和分类。[`Pipeline`](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html#sklearn.pipeline.Pipeline "sklearn.pipeline.Pipeline") 在这里有多种用途:
W
init  
wizardforcel 已提交
14

L
loopyme 已提交
15 16 17
* **便捷性和封装性** 你只要对数据调用 `fit``predict` 一次来适配所有的一系列评估器。
* **联合的参数选择** 你可以一次`grid search`管道中所有评估器的参数。
* **安全性** 训练转换器和预测器使用的是相同样本,管道有助于防止来自测试数据的统计数据泄露到交叉验证的训练模型中。
W
init  
wizardforcel 已提交
18 19 20

管道中的所有评估器,除了最后一个评估器,管道的所有评估器必须是转换器。 (例如,必须有 `transform` 方法). 最后一个评估器的类型不限(转换器、分类器等等)

L
loopyme 已提交
21
### 5.1.1.1. 用法
L
loopyme 已提交
22 23 24 25 26 27 28 29 30 31 32 33 34
#### 5.1.1.1.1. 构造
[`Pipeline`](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html#sklearn.pipeline.Pipeline "sklearn.pipeline.Pipeline") 使用一系列 `(key, value)` 键值对来构建,其中 `key` 是你给这个步骤起的名字, `value` 是一个评估器对象:
```py
>>> 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)
```
W
init  
wizardforcel 已提交
35

36
功能函数 [`make_pipeline`](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.make_pipeline.html#sklearn.pipeline.make_pipeline "sklearn.pipeline.make_pipeline") 是构建管道的缩写; 它接收多个评估器并返回一个管道,自动填充评估器名:
W
init  
wizardforcel 已提交
37 38 39 40 41

```py
>>> from sklearn.pipeline import make_pipeline
>>> from sklearn.naive_bayes import MultinomialNB
>>> from sklearn.preprocessing import Binarizer
L
loopyme 已提交
42
>>> make_pipeline(Binarizer(), MultinomialNB())
W
init  
wizardforcel 已提交
43
Pipeline(memory=None,
L
loopyme 已提交
44 45 46 47 48
         steps=[('binarizer', Binarizer(copy=True, threshold=0.0)),
                ('multinomialnb', MultinomialNB(alpha=1.0,
                                                class_prior=None,
                                                fit_prior=True))],
         verbose=False)
W
init  
wizardforcel 已提交
49 50
```

L
loopyme 已提交
51 52
#### 5.1.1.1.2. 访问步骤
管道中的评估器作为一个列表保存在 `steps` 属性内,但可以通过索引或名称([idx])访问管道:
W
init  
wizardforcel 已提交
53 54

```py
L
loopyme 已提交
55 56 57 58 59 60 61 62 63
>>> 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, ...)
W
init  
wizardforcel 已提交
64 65
```

L
loopyme 已提交
66
管道的`named_steps`属性允许在交互式环境中使用tab补全,以按名称访问步骤:
W
init  
wizardforcel 已提交
67
```py
L
loopyme 已提交
68 69
>> pipe.named_steps.reduce_dim is pipe['reduce_dim']
True
W
init  
wizardforcel 已提交
70 71
```

L
loopyme 已提交
72
还可以使用通常用于Python序列(如列表或字符串)的切片表示法提取子管道(尽管只允许步骤1)。这对于只执行一些转换(或它们的逆)是很方便的:
W
init  
wizardforcel 已提交
73
```py
L
loopyme 已提交
74 75 76 77
>>> pipe[:1]
Pipeline(memory=None, steps=[('reduce_dim', PCA(copy=True, ...))],...)
>>> pipe[-1:]
Pipeline(memory=None, steps=[('clf', SVC(C=1.0, ...))],...)
W
init  
wizardforcel 已提交
78 79
```

L
loopyme 已提交
80
#### 5.1.1.1.3. 嵌套参数
W
init  
wizardforcel 已提交
81

L
loopyme 已提交
82
管道中的评估器参数可以通过 `<estimator>__<parameter>` 语义来访问:
W
init  
wizardforcel 已提交
83

L
loopyme 已提交
84 85 86 87 88 89
```py
>>> 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)
W
init  
wizardforcel 已提交
90 91 92 93 94 95 96 97 98 99 100
```

这对网格搜索尤其重要:

```py
>>> 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)
```

L
loopyme 已提交
101
单独的步骤可以用多个参数替换,除了最后步骤,其他步骤都可以设置为 `passthrough` 来跳过
W
init  
wizardforcel 已提交
102 103 104

```py
>>> from sklearn.linear_model import LogisticRegression
L
loopyme 已提交
105
>>> param_grid = dict(reduce_dim=['passthrough', PCA(5), PCA(10)],
W
init  
wizardforcel 已提交
106 107 108 109 110
...                   clf=[SVC(), LogisticRegression()],
...                   clf__C=[0.1, 10, 100])
>>> grid_search = GridSearchCV(pipe, param_grid=param_grid)
```

L
loopyme 已提交
111
管道的估计量可以通过索引检索:
W
init  
wizardforcel 已提交
112

L
loopyme 已提交
113 114 115 116
```py
>>> pipe[0]  
PCA(copy=True, ...)
```
W
init  
wizardforcel 已提交
117

L
loopyme 已提交
118 119 120 121 122 123 124
> **示例** :
>*   [Pipeline Anova SVM](https://scikit-learn.org/stable/auto_examples/feature_selection/plot_feature_selection_pipeline.html#sphx-glr-auto-examples-feature-selection-plot-feature-selection-pipeline-py)
>*   [Sample pipeline for text feature extraction and evaluation](https://scikit-learn.org/stable/auto_examples/model_selection/grid_search_text_feature_extraction.html#sphx-glr-auto-examples-model-selection-grid-search-text-feature-extraction-py)
>*   [Pipelining: chaining a PCA and a logistic regression](https://scikit-learn.org/stable/auto_examples/plot_digits_pipe.html#sphx-glr-auto-examples-plot-digits-pipe-py)
>*   [Explicit feature map approximation for RBF kernels](https://scikit-learn.org/stable/auto_examples/plot_kernel_approximation.html#sphx-glr-auto-examples-plot-kernel-approximation-py)
>*   [SVM-Anova: SVM with univariate feature selection](https://scikit-learn.org/stable/auto_examples/svm/plot_svm_anova.html#sphx-glr-auto-examples-svm-plot-svm-anova-py)
>*   [Selecting dimensionality reduction with Pipeline and GridSearchCV](https://scikit-learn.org/stable/auto_examples/plot_compare_reduction.html#sphx-glr-auto-examples-plot-compare-reduction-py)
W
init  
wizardforcel 已提交
125

L
loopyme 已提交
126
>也可以参阅:
L
loopyme 已提交
127
>*   [调整估计器的超参数](/docs/31#32-调整估计器的超参数)
W
init  
wizardforcel 已提交
128

L
loopyme 已提交
129
### 5.1.1.2. 注意
W
init  
wizardforcel 已提交
130

V
VPrincekin 已提交
131
对管道调用 `fit` 方法的效果跟依次对每个评估器调用 `fit` 方法一样, 都是``transform`` 输入并传递给下个步骤。 管道中最后一个评估器的所有方法,管道都有。例如,如果最后的评估器是一个分类器, [`Pipeline`](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html#sklearn.pipeline.Pipeline "sklearn.pipeline.Pipeline") 可以当做分类器来用。如果最后一个评估器是转换器,管道也一样可以。
W
init  
wizardforcel 已提交
132

L
loopyme 已提交
133
### 5.1.1.3. 缓存转换器:避免重复计算
W
init  
wizardforcel 已提交
134

片刻小哥哥's avatar
片刻小哥哥 已提交
135
适配转换器是很耗费计算资源的。设置了``memory`` 参数, [`Pipeline`](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html#sklearn.pipeline.Pipeline "sklearn.pipeline.Pipeline") 将会在调用``fit``方法后缓存每个转换器。 如果参数和输入数据相同,这个特征用于避免重复计算适配的转换器。典型的示例是网格搜索转换器,该转化器只要适配一次就可以多次使用。
W
init  
wizardforcel 已提交
136

L
loopyme 已提交
137
`memory` 参数用于缓存转换器。`memory` 可以是包含要缓存的转换器的目录的字符串或一个 [joblib.Memory](https://pythonhosted.org/joblib/memory.html) 对象:
W
init  
wizardforcel 已提交
138 139 140 141 142 143 144 145 146 147

```py
>>> 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)
L
loopyme 已提交
148
>>> pipe
W
init  
wizardforcel 已提交
149
Pipeline(...,
L
loopyme 已提交
150 151
         steps=[('reduce_dim', PCA(copy=True,...)),
                ('clf', SVC(C=1.0,...))], verbose=False)
W
init  
wizardforcel 已提交
152 153 154 155 156
>>> # Clear the cache directory when you don't need it anymore
>>> rmtree(cachedir)
```


L
loopyme 已提交
157 158 159
>**警告**:缓存转换器的副作用
>
>使用 [`Pipeline`](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html#sklearn.pipeline.Pipeline "sklearn.pipeline.Pipeline") 而不开启缓存功能,还是可以通过查看原始实例的,例如:
160 161
>
```py
L
loopyme 已提交
162 163 164 165 166 167 168 169 170 171 172 173
  >>> 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
  >>> print(pca1.components_)
      [[-1.77484909e-19  ... 4.07058917e-18]]
174
```
片刻小哥哥's avatar
片刻小哥哥 已提交
175
>开启缓存会在适配前触发转换器的克隆。因此,管道的转换器实例不能被直接查看。 在下面示例中, 访问 `PCA` 实例 `pca2` 将会引发 `AttributeError` 因为 `pca2` 是一个未适配的转换器。 这时应该使用属性 `named_steps` 来检查管道的评估器:
176 177
>
```py
L
loopyme 已提交
178 179 180
  >>> cachedir = mkdtemp()
  >>> pca2 = PCA()
  >>> svm2 = SVC(gamma='scale')
181
  >>> cached_pipe = Pipeline([('reduce_dim', pca2), ('clf', svm2)],memory=cachedir)
L
loopyme 已提交
182 183 184 185 186 187 188 189 190 191
  >>> 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)
192
```
L
loopyme 已提交
193 194 195 196

> **示例** :
>*   [Selecting dimensionality reduction with Pipeline and GridSearchCV](https://scikit-learn.org/stable/auto_examples/plot_compare_reduction.html#sphx-glr-auto-examples-plot-compare-reduction-py)

L
loopyme 已提交
197
## 5.1.2. 回归中的目标转换
L
loopyme 已提交
198 199

`TransformedTargetRegressor`在拟合回归模型之前对目标`y`进行转换。这些预测通过一个逆变换被映射回原始空间。它以预测所用的回归器为参数,将应用于目标变量的变压器为参数:
W
init  
wizardforcel 已提交
200 201

```py
L
loopyme 已提交
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
>>> 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
W
init  
wizardforcel 已提交
223 224
```

L
loopyme 已提交
225
对于简单的变换,可以传递一对函数,而不是一个Transformer对象,定义变换及其逆映射:
W
init  
wizardforcel 已提交
226
```py
L
loopyme 已提交
227 228 229 230 231
>>> def func(x):
...     return np.log(x)
>>> def inverse_func(x):
...     return np.exp(x)
```
W
init  
wizardforcel 已提交
232

L
loopyme 已提交
233 234 235 236 237 238 239 240 241
随后,对象被创建为:
```py
>>> 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
W
init  
wizardforcel 已提交
242 243
```

L
loopyme 已提交
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
默认情况下,所提供的函数在每次匹配时都被检查为彼此的倒数。但是,可以通过将`check_reverse`设置为`False`来绕过这个检查:
```py
>>> 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
```
>**注意**
>可以通过设置transformer或函数对func和inverse_func来触发转换。但是,同时设置这两个选项会产生错误。
W
init  
wizardforcel 已提交
259

片刻小哥哥's avatar
片刻小哥哥 已提交
260
>**示例**
L
loopyme 已提交
261
>* [Effect of transforming the targets in regression model](https://scikit-learn.org/stable/auto_examples/compose/plot_transformed_target.html#sphx-glr-auto-examples-compose-plot-transformed-target-py)
W
init  
wizardforcel 已提交
262

L
loopyme 已提交
263
## 5.1.3. FeatureUnion(特征联合): 复合特征空间
W
init  
wizardforcel 已提交
264

265
[`FeatureUnion`](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.FeatureUnion.html#sklearn.pipeline.FeatureUnion "sklearn.pipeline.FeatureUnion") 合并了多个转换器对象形成一个新的转换器,该转换器合并了他们的输出。一个 [`FeatureUnion`](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.FeatureUnion.html#sklearn.pipeline.FeatureUnion "sklearn.pipeline.FeatureUnion") 可以接收多个转换器对象。在适配期间,每个转换器都单独的和数据适配。 对于转换数据,转换器可以并发使用,且输出的样本向量被连接成更大的向量。
W
init  
wizardforcel 已提交
266

267
[`FeatureUnion`](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.FeatureUnion.html#sklearn.pipeline.FeatureUnion "sklearn.pipeline.FeatureUnion") 功能与 [`Pipeline`](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html#sklearn.pipeline.Pipeline "sklearn.pipeline.Pipeline") 一样- 便捷性和联合参数的估计和验证。
W
init  
wizardforcel 已提交
268

L
loopyme 已提交
269
可以结合:`FeatureUnion`[`Pipeline`](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html#sklearn.pipeline.Pipeline "sklearn.pipeline.Pipeline") 来创造出复杂模型。
W
init  
wizardforcel 已提交
270

271
(一个 [`FeatureUnion`](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.FeatureUnion.html#sklearn.pipeline.FeatureUnion "sklearn.pipeline.FeatureUnion") 没办法检查两个转换器是否会产出相同的特征。它仅仅在特征集合不相关时产生联合并确认是调用者的职责。)
W
init  
wizardforcel 已提交
272

L
loopyme 已提交
273
### 5.1.3.1. 用法
W
init  
wizardforcel 已提交
274

275
一个 [`FeatureUnion`](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.FeatureUnion.html#sklearn.pipeline.FeatureUnion "sklearn.pipeline.FeatureUnion") 是通过一系列 `(key, value)` 键值对来构建的,其中的 `key` 给转换器指定的名字 (一个绝对的字符串; 他只是一个代号), `value` 是一个评估器对象:
W
init  
wizardforcel 已提交
276 277 278 279 280 281 282

```py
>>> 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)
L
loopyme 已提交
283
>>> combined
L
loopyme 已提交
284 285 286 287
FeatureUnion(n_jobs=None,
             transformer_list=[('linear_pca', PCA(copy=True,...)),
                               ('kernel_pca', KernelPCA(alpha=1.0,...))],
             transformer_weights=None, verbose=False)
W
init  
wizardforcel 已提交
288 289
```

L
loopyme 已提交
290 291


292
跟管道一样,特征联合有一个精简版的构造器叫做:func:*make_union* ,该构造器不需要显式给每个组价起名字。
W
init  
wizardforcel 已提交
293

L
loopyme 已提交
294 295
正如 `Pipeline`, 单独的步骤可能用``set_params``替换 ,并设置为`drop`来跳过:

W
init  
wizardforcel 已提交
296 297

```py
L
loopyme 已提交
298
>>> combined.set_params(kernel_pca='drop')
L
loopyme 已提交
299
...
L
loopyme 已提交
300 301 302 303 304 305 306 307
FeatureUnion(n_jobs=None,
             transformer_list=[('linear_pca', PCA(copy=True,...)),
                               ('kernel_pca', 'drop')],
             transformer_weights=None, verbose=False)
```

> **示例** :
>*   [Concatenating multiple feature extraction methods](https://scikit-learn.org/stable/auto_examples/plot_feature_stacker.html#sphx-glr-auto-examples-plot-feature-stacker-py)
W
init  
wizardforcel 已提交
308

L
loopyme 已提交
309
## 5.1.4. 用于异构数据的列转换器
L
loopyme 已提交
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
>**警告**:[compose.ColumnTransformer](https://scikit-learn.org/stable/modules/generated/sklearn.compose.ColumnTransformer.html#sklearn.compose.ColumnTransformer) 还在实验中,它的 API可能会变动的。

许多数据集包含不同类型的特性,比如文本、浮点数和日期,每种类型的特征都需要单独的预处理或特征提取步骤。 通常,在应用scikit-learn方法之前,最容易的是对数据进行预处理,例如 [pandas](http://pandas.pydata.org/)。 在将数据传递给scikit-learn之前处理数据可能会出现问题,原因如下:
* 将来自测试数据的统计信息集成到预处理程序中,使得交叉验证分数不可靠(被称为数据泄露)。 例如,在尺度变换或计算缺失值的情况下。
* 你可能想要在`parameter search`中包含预处理器参数。

[compose.ColumnTransformer](https://scikit-learn.org/stable/modules/generated/sklearn.compose.ColumnTransformer.html#sklearn.compose.ColumnTransformer)对数据的不同列执行不同的变换,该管道不存在数据泄漏,并且可以参数化。ColumnTransformer可以处理数组、稀疏矩阵和[pandas DataFrames](https://pandas.pydata.org/pandas-docs/stable/)

对每一列,都会应用一个不同的变换, 比如preprocessing或某个特定的特征抽取方法:

```py
>>> 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”。默认情况下,忽略其余的ranking列(`remainder='drop'`):

```py
>>> from sklearn.compose import ColumnTransformer
>>> from sklearn.feature_extraction.text import CountVectorizer
>>> column_trans = ColumnTransformer(
...     [('city_category', CountVectorizer(analyzer=lambda x: [x]), '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__London', 'city_category__Paris', 'city_category__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]]...)
W
init  
wizardforcel 已提交
359
```
片刻小哥哥's avatar
片刻小哥哥 已提交
360
在上面的示例中,`CountVectorizer`希望接受一维数组作为输入,因此列被指定为字符串(`'title'`)。然而,`preprocessing.OneHotEncoder`就像大多数其他转换器一样,期望2D数据,因此在这种情况下,您需要将列指定为字符串列表(`['city']`)。
L
loopyme 已提交
361 362

除了标量或单个项列表外,列选择可以指定为多个项、整数数组、片或布尔掩码的列表。如果输入是DataFrame,则字符串可以引用列,整数总是解释为位置列。
W
init  
wizardforcel 已提交
363

L
loopyme 已提交
364 365 366 367 368 369
我们可以通过设置`remainder='passthrough'`来保留其余的ranking列。这些值被附加到转换的末尾:
```py
>>> column_trans = ColumnTransformer(
...     [('city_category', OneHotEncoder(dtype='int'),['city']),
...      ('title_bow', CountVectorizer(), 'title')],
...     remainder='passthrough')
W
init  
wizardforcel 已提交
370

L
loopyme 已提交
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
>>> 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`设置为estimator来转换剩余的ranking列。转换后的值被附加到转换的末尾:
```py
>>> 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. ]])
```
片刻小哥哥's avatar
片刻小哥哥 已提交
393
函数 [`make_column_transformer`](https://scikit-learn.org/stable/modules/generated/sklearn.compose.make_column_transformer.html#sklearn.compose.make_column_transformer)可用来更简单的创建类对象 [`ColumnTransformer`](https://scikit-learn.org/stable/modules/generated/sklearn.compose.ColumnTransformer.html#sklearn.compose.ColumnTransformer) 。 特别的,名字将会被自动给出。上面的示例等价于
L
loopyme 已提交
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
```py
>>> 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', ...)
```
> **示例**
>* [Column Transformer with Heterogeneous Data Sources](https://scikit-learn.org/stable/auto_examples/compose/plot_column_transformer.html#sphx-glr-auto-examples-compose-plot-column-transformer-py)
>* [Column Transformer with Mixed Types](https://scikit-learn.org/stable/auto_examples/compose/plot_column_transformer_mixed_types.html#sphx-glr-auto-examples-compose-plot-column-transformer-mixed-types-py)