Pipeline类补单可以用于预处理和分类,实际上还可以将任意数量的估计器连接在一起。例如,我们可以构建一个包含特征提取、特征选择、缩放和分类的管道,总共有4个步骤。同样的,最后一步可以用聚类或回归代替。
对于管道中估计器的唯一压球就是,除了最后一步之外的所有步骤都需要具有transform方法,这样它们可以生成新的数据表示,以供下一个步骤使用。
在调用Pipeline.fit的过程中,管道内部依次对每个步骤调用fit和transform,其输入的前一个步骤中transform方法的输出。对于管道的最后一步,则仅调用fit。
实现方法如下。要记住,pipeline.steps是由元祖组成的列表,所以pipeline.steps[0][1]是第一个估计器,pipeline.steps[1][1]是第二个估计器,以此类推:
def fit(self,X,y):X_transformed=Xfor name,estimators in self.steps[:-1]:#遍历除最后一步之外的所有步骤#对数据进行拟合和变换X_transformed=estimators.fit_transform(X_transformed,y)self.steps[-1][1].fit(X_transformed,y)return self
使用Pipeline进行预测时,我们同样利用除最后一步之外的所有步骤对数据进行变换(transform),然后对最后一步调用predict:
def predict(self,X):X_transformed = Xfor step in self.steps[:-1]:# 遍历除最后一步之外的所有步骤# 对数据进行变换X_transformed=step[1].transform(X_transformed)return self.steps[-1][1].predict(X_transformed)
整个过程包含两个变换器(transformer),还有一个分类器。
管道的最后一步不需要具有predict函数,比如说,我们可以创建一个只包含一个缩放器和一个PCA的管道。由于最后一步(PCA)具有transform方法,所以我们可以对管道调用transform,已得到将PCA.transform应用于前一个步骤处理过的数据后得到的输出。
管道的最后一步只需要具有fit方法。
1、用make_pipeline方便的创建管道
我们通常不需要为每个步骤提供用户指定的名称,有一个很方便的函数make_pipeline,可以为我们创建管道并根据每个步骤所属的类为其自动命名。
make_pipeline的语法如下:
from sklearn.pipeline import make_pipeline#标准写法
pipe_long=Pipeline([('scaler',MinMaxScaler()),('svm',SVC(C=100))])
#缩写语法
pipe_short=make_pipeline(MinMaxScaler(),SVC(C=100))
管道对象pipe_long和pipe_short的作用完全相同,但pipe_short的步骤是自动命名的。
我们可以通过查看steps属性来查看步骤的名称:
print('步骤名称:{}'.format(pipe_short.steps))
这两个步骤被命名为minmaxscaler和svc,通常来说,步骤名称只是类名称的小写版本。如果是多个步骤属于同一个类,则会附加一个数字:
pipe=make_pipeline(StandardScaler(),PCA(n_components=2),StandardScaler())
print('步骤名称:{}'.format(pipe.steps))
但是这种情况下,使用更有明确名称的Pipeline构建可能更好,以便于为每个步骤提供更有语义的名称。
2、访问步骤属性
通常来说,如果我们想要检查管道中某一步骤的属性(比如线性模型的系数或PCA提供的成分),最简单的方法是通过named_steps属性,它是一个字典,将步骤名称映射为估计器:
cancer=load_breast_cancer()
pipe.fit(cancer.data)
#从pca步骤提取前两个主成分
components=pipe.named_steps['pca'].components_
print('主成分shape:{}'.format(components.shape))
3、访问网格搜索管道中的属性
使用管道的主要原因之一就是进行网格搜索。一个常见的任务就是在网格搜索内访问管道的某些步骤。
我们对cancer数据上的LogisticRegression分类器进行网格搜索,在将数据传入LogisticRegression分类器之前,先用Pipeline和StandardScaler对数据进行缩放。
首先,我们用make_pipeline函数创建一个管道:
cancer=load_breast_cancer()
pipe=make_pipeline(StandardScaler(),LogisticRegression())
接下来,创建一个参数网格。LogisticRegression需要调节的正则化参数是参数C,我们对这个参数使用对数网格,在0.01和100之间进行搜索。由于我们使用了make_pipeline哈数,所以管道中LogisticRegression步骤的名称是小写的logisticregression。因此,为了调节参数C,我们必须指定logisticregression__C的参数网格:
param_grid={'logisticregression__C':[0.01,0.1,1,10,100]}
我们将cancer数据集划分为训练集和测试集,并对网格搜索进行拟合:
X_train,X_test,y_train,y_test=train_test_split(cancer.data,cancer.target,random_state=4)
grid=GridSearchCV(pipe,param_grid=param_grid,cv=5)
grid.fit(X_train,y_train)
GridSearchCV找到的最佳模型保存在best_estimator_中:
print('最佳模型:{}'.format(grid.best_estimator_))
在这个例子中,best_estimator_是一个管道,它包含两个步骤:standardscaler和logisticregression。我们可以使用管道的named_steps属性来访问logisticregression步骤:
print('logisticregression步骤:{}'.format(grid.best_estimator_.named_steps['logisticregression']))
现在我们得到了训练过的LogisticRegression实例。下面可以访问与每个输入特征相关的系数(权重):
print('logisticregression权重:{}'.format(grid.best_estimator_.named_steps['logisticregression'].coef_))