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_))