Scikit-learn流水线原理与实践

本文将介绍scikit-learn的工作原理与实现方法,以及如何应用 到模型训练、数据预测、模型选择和模型参数搜索的处理流程中。

在大多数机器学习项目中,你要处理的数据不大可能恰好是生成最优模型的 理想格式。有很多数据变换的步骤例如分类变量编码、特征缩放和归一化需要 执行。Scikit-learn的预处理模块中包含了内建的函数来支持这些常用的变换。

但是,在一个典型的机器学习工作流中你将需要应用这些变换至少两次。 一次是在训练时,另一次是在你要用模型预测新数据时。当然你可以写 一个函数来重用这些变换,但是你还是需要首先运行这个函数,然后再 调用模型。Scikit-learn的流水线/pipeline就是一个简化此操作的工具, 具有如下优点:

  • 让工作流程更加简单易懂
  • 强制步骤实现和执行顺序
  • 让工作更加可重现

在本文中,我将使用一个贷款预测方面的数据集,来介绍流水线的工作 原理以及实现方法。

1、变换器 / Transformer

首先我将训练和测试文件导入jypyter notebook。我删除了Load_ID 列,因为在训练和预测中并不需要它。我使用pandas的dtypes函数来获取 数据集的简要信息:

1
2
3
4
5
import pandas as pd
train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')
train = train.drop('Loan_ID', axis=1)
train.dtypes

可以看到数据中既有分类变量也有数值变量,因此我至少需要应用 one-hot编码变换以及某种尺度的缩放。我使用scikit-learn的流水线 来执行这些变换,同时应用fit方法进行训练。

在构建流水线之前我将训练数据拆分为训练集和测试集,这样我可以 验证模型的性能:

1
2
3
4
5
6
X = train.drop('Loan_Status', axis=1)
y = train['Loan_Status']

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

构造流水线的第一步是定义变换器类型。在下面的代码中,我创建了 一个运用StandardScaler的数值变换器,它同时包含了一个SimpleImputer 来填充丢失的值。这是scikit-learn中的一个相当出色的函数,它有很多 选项来定义如何填充丢失值。我选择使用中位数据(median)但是也 可能其他选项会有更好的效果。分类变换器也有一个支持各种填充方法的 SimpleImputer,燃火利用OneHotEncoder将分类值转换为整数:

1
2
3
4
5
6
7
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from 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变换数据帧中的列。在此之前已经 使用pandas的dtype方法进行了列表排序:

1
2
3
4
5
6
7
8
9
numeric_features = train.select_dtypes(include=['int64', 'float64']).columns
categorical_features = train.select_dtypes(include=['object']).drop(['Loan_Status'], axis=1).columns

from sklearn.compose import ColumnTransformer

preprocessor = ColumnTransformer(
transformers=[
('num', numeric_transformer, numeric_features),
('cat', categorical_transformer, categorical_features)])

2、分类器训练

接下来的步骤是创建一个流水线将前面创建的预处理器与分类器整合在一起。 在这里我使用一个简单的RandomForestClassifier:

1
2
3
4
from sklearn.ensemble import RandomForestClassifier

rf = Pipeline(steps=[('preprocessor', preprocessor),
('classifier', RandomForestClassifier())])

你可以简单地对原始数据调用fit方法,预处理步骤将会先执行,然后再 训练分类器:

1
rf.fit(X_train, y_train)

要预测新数据也一样,流水线也会先进行预处理,然后再进行预测:

1
y_pred = rf.predict(X_test)

3、模型选择

流水线可以用于模型选择过程。下面的示例代码对一组scikit-learn分类器 逐个应用变换并训练模型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from sklearn.metrics import accuracy_score, log_loss
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC, LinearSVC, NuSVC
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier, AdaBoostClassifier, GradientBoostingClassifier
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from 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))

4、模型参数搜索

流水线也可以用于网格搜索(grid search)以找到模型的最佳参数。 为此我们需要首先为模型创建一个参数网格。重要的一点是你需要 给每个参数名添加分类器的名称。在上面的代码中我将分类器命名 为classifier,因此我给每个参数都添加了classifier__。接下来 我创建一个网格搜索对象,它包含了原始的流水线。当我调用fit 方法时,就会在网格搜索交叉验证之前首先对数据执行变换。

1
2
3
4
5
6
7
8
9
10
11
12
13
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 GridSearchCV

CV = GridSearchCV(rf, param_grid, n_jobs= 1)

CV.fit(X_train, y_train)
print(CV.best_params_)
print(CV.best_score_)

在我开始使用流水线之前,经常发现我看不懂以前某个项目的处理 流程了。流水线让整个机器学习流程清晰易懂,容易维护。希望这个 教程对你学习scikit-learn的pipeline有所帮助。


原文链接:A Simple Guide to Scikit-learn Pipelines

汇智网翻译整理,转载请标明出处