本文翻译自:https://medium.com/vickdata/a-simple-guide-to-scikit-learn-pipelines-4ac0d974bdcf
使用 Scikit-learn Pipeline 可以很容易地将机器学习中的步骤串联起来,简化流程大幅度减少代码冗余,方便结果复现。

Pipeline 中除最后一个 estimators 外的所有估计器都须是 transformer。最后一个 estimator 可以是任何类型(transformer,classifier,regresser)。在今天的教程中,我们将使用 Analytics Vidhya 上的 loan prediction 数据集( https://datahack.analyticsvidhya.com/contest/practice-problem-loan-prediction-iii/ ),尝试将数据预处理和机器学习建模组织在一起形成一个典型的机器学习工作流程。
数据预处理
首先,将数据载入 jupyter notebook,删除 Loan_ID 列,用 dtypes 查看特征的数据类型:
import pandas as pdtrain = pd.read_csv('train.csv')test = pd.read_csv('test.csv')train = train.drop('Loan_ID', axis=1)train.dtypes

可以看到这个数据集中包含了分类变量和数值变量,所以我们需要对分类变量进行独热编码以及归一化。下面我们将用 scikit-learn pipeline 进行这些转换。
在构建 pipeline 之前,我们先将训练数据分为训练和测试集,以便评估模型性能。
X = train.drop('Loan_Status', axis=1)y
= train['Loan_Status']from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
建立 pipeline 的第一步是定义每种转换器的类型。我们通常为不同的变量类型创建不同的转换器。在下面的代码中,我们先是创建了一个数值转换器 numeric_transformer 用 StandardScaler() 进行归一化,同时用 SimpleImputer(strategy='median') 来填充缺失值。针对分类变量,我们定义 categorical_transformer ,同样用 SimpleImputer() 填充缺失值,并用 OneHotEncoder() 将分类变量转换为整数。
from sklearn.pipeline import Pipelinefrom sklearn.impute import SimpleImputerfrom sklearn.preprocessing import StandardScaler, OneHotEncodernumeric_transformer = Pipeline(steps=[ ('imputer', SimpleImputer(strategy='median')), ('scaler', StandardScaler())])categorical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='constant', fill_value='missing')), ('onehot', OneHotEncoder(handle_unknown='ignore'))])
接下来,用 ColumnTransformer 确定每列数据对应的数据转换类型。
numeric_features = train.select_dtypes(include=['int64', 'float64']).columnscategorical_features = train.select_dtypes(include=['object']).drop(['Loan_Status'], axis=1).columnsfrom sklearn.compose import ColumnTransformerpreprocessor = ColumnTransformer( transformers=[ ('num', numeric_transformer, numeric_features), ('cat', categorical_transformer, categorical_features)])
拟合分类器
下一步是创建将上面创建的预处理器与分类器结合在一起的 pipeline 。这里以一个简单的 RandomForestClassifier 为例。我们将参数传入一个列表,列表中的每个元素是管道中的一个步骤。每个元素是一个元组,元组的第一个元素是名字(字符串),第二个元素是实例化。
from
sklearn.ensemble import RandomForestClassifierrf = Pipeline(steps=[('preprocessor', preprocessor), ('classifier', RandomForestClassifier())])
然后,我们就可以直接对数据调用 fit 方法,pipeline 就会按照我们预设的流程进行数据预处理,然后训练分类器。
如果要对新数据进行预测,我们也可以很方便地调用 predict 进行数据预处理和训练分类器。
y_pred = rf.predict(X_test)
模型选择
Pipeline 还可以用于模型选择。下面的示例中我们就尝试了许多 scikit-learn 分类器进行模型选择。
from sklearn.metrics import accuracy_score, log_lossfrom sklearn.neighbors import KNeighborsClassifierfrom sklearn.svm import SVC, LinearSVC, NuSVCfrom sklearn.tree import DecisionTreeClassifierfrom sklearn.ensemble import RandomForestClassifier
, AdaBoostClassifier, GradientBoostingClassifierfrom sklearn.discriminant_analysis import LinearDiscriminantAnalysisfrom sklearn.discriminant_analysis import QuadraticDiscriminantAnalysisclassifiers = [ KNeighborsClassifier(3), SVC(kernel="rbf", C=0.025, probability=True), NuSVC(probability=True), DecisionTreeClassifier(), RandomForestClassifier(), AdaBoostClassifier(), GradientBoostingClassifier() ]for classifier in classifiers: pipe = Pipeline(steps=[('preprocessor', preprocessor), ('classifier', classifier)]) pipe.fit(X_train, y_train)
print(classifier) print("model score: %.3f" % pipe.score(X_test, y_test))

除此之外,Pipeline 可结合网格搜索以找到性能最佳的模型参数。第一步是为所选模型创建参数网格。需要注意的是,这里需要把分类器的名称附加到每个参数名称中,比如在上面的随机森林建模代码中,我们将分类器的名称定义为 classifier,所以这里就需要在每个参数前添加 classifier__ 的前缀。接下来,我创建一个包含原始 pipeline 的网格搜索对象。这样当我们进行网格搜索时,都会包含数据预处理以及用相应参数创建模型的步骤。
param_grid = { 'classifier__n_estimators': [200, 500], 'classifier__max_features': ['auto', 'sqrt', 'log2'], 'classifier__max_depth' : [4,5,6,7,8], 'classifier__criterion' :['gini', 'entropy']}from sklearn.model_selection import GridSearchCVCV = GridSearchCV(rf, param_grid, n_jobs=
1)
CV.fit(X_train, y_train)print(CV.best_params_)print(CV.best_score_)
虽然我已经用 scikit-learn 进行了许多机器学习项目。但在学习 pipeline 之前,我也很难完全重复之前的实验结果。Pipeline 使我的项目易于重复且具可扩展性,希望本文也能对大家有所帮助。