如您所见,有许多数据转换步骤需要以正确的顺序执行。幸运的是,Scikit-Learn 提供了Pipeline类来帮助进行这样的转换的序列。这是一个用于数值属性的小管道:

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
num_pipeline = Pipeline([
        ('imputer', Imputer(strategy="median")),
        ('attribs_adder', CombinedAttributesAdder()),
        ('std_scaler', StandardScaler()),
    ])
housing_num_tr = num_pipeline.fit_transform(housing_num)

Pipeline构造函数接受定义一系列步骤的元组列表,而该元组则是一个name/estimator(即名字/估计其器)的二元元组。除了最后一个是估计器之外,其他的都是转换器(它们必须有一个fit_transform()方法),而元组里的name则可以任意起名字。

当您调用管道的fit()方法时,它会对所有的转换器依次调用fit_transform(),将每个调用的输出作为参数传递给下一个调用,直到它到达最终的估计器,对于它,我们只调用它的fit()方法。

管道暴露了与最终的估计器相同的方法。在这个例子中,最后的估计器是StandardScaler,它是一个转换器,因此管道有一个transform()方法,按顺序将所有的转换应用到数据上(它也有一个fit_transform方法,我们可以使用它来替换掉先调用 fit(),再调用transform()的两步操作)。

现在您有了一个用于数值的管道,您还需要将LabelBinarizer应用于分类值:如何将这些转换连接到一个单一管道中? Scikit-Learn为这个提供了一个FeatureUnion类。你给它一个转换器列表(可整个变压器管道),当其transform()方法被调用时,它会并行的运行每个转换器的 transform()方法,并等待他们的输出,然后连接它们并返回结果(当然,调用它的fit()方法,也会调用每个转换器的fit()方法)。一个完整的处理数值和分类属性的管道可能像这样:

from sklearn.pipeline import FeatureUnion
num_attribs = list(housing_num)
cat_attribs = ["ocean_proximity"]
num_pipeline = Pipeline([
        ('selector', DataFrameSelector(num_attribs)),
        ('imputer', Imputer(strategy="median")),
        ('attribs_adder', CombinedAttributesAdder()),
        ('std_scaler', StandardScaler()),
        ])
cat_pipeline = Pipeline([
        ('selector', DataFrameSelector(cat_attribs)),
        ('label_binarizer', LabelBinarizer()),
        ])
full_pipeline = FeatureUnion(transformer_list=[
        ("num_pipeline", num_pipeline),
        ("cat_pipeline", cat_pipeline),
        ])

你可以简单地运行整个管道:

>>> housing_prepared = full_pipeline.fit_transform(housing)
>>> housing_prepared
array([[ 0.73225807, -0.67331551, 0.58426443, ..., 0. ,
0. , 0. ],
[-0.99102923, 1.63234656, -0.92655887, ..., 0. ,
0. , 0. ],
[...]
>>> housing_prepared.shape
(16513, 17)

每个子管道都从一个叫selector的转换器开始:它只是通过选择所需的属性(数值或分类)来转换数据,放弃其余的属性,并将结果的DataFrame转换为一个NumPy数组。在Scikit-Learn中没有任何东西可以用来处理Pandas的数据,所以我们需要为这个任务编写一个简单的自定义转换器:

from sklearn.base import BaseEstimator, TransformerMixin
class DataFrameSelector(BaseEstimator, TransformerMixin):
    def __init__(self, attribute_names):
        self.attribute_names = attribute_names
    def fit(self, X, y=None):
        return self
    def transform(self, X):
        return X[self.attribute_names].values

results matching ""

    No results matching ""