本章介绍了Pipeline类,这是一种通用工具,可以将机器学习工作流程中的多个处理步骤链接在一起。现实世界中的机器学习应用很少仅涉及模型的单独使用,而是需要一系列处理步骤。 使用管道可以将多个步骤封装为单个Python对象,这个对象具有我们熟悉的scikit-learn接口fit、predict、和transform。特别是使用交叉验证进行模型评估与使用网格搜索进行参数选择时,使用Pipeline类来包括所有处理步骤对正确的评估至关重要。利用Pipeline类还可以让代码更加简洁,并减少不用Pipeline类构建处理链时可能会犯的错误(比如忘记将所有变换器应用于测试集,或者应用顺序错误)的可能性。选择特征提取、预处理和模型的正确组合,这在某种程度上是一种艺术,通常需要一些试错。但是有了管道,这种“尝试”多个不同的处理步骤是非常简单的。在进行试验时,要小心不要将处理过程复杂化,并且一定要评估一下模型的每个组件是否必要。
举一个例子来说明模型的重要性:
from sklearn.svm import SVC
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
# load and split the data
cancer = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
cancer.data, cancer.target, random_state=0)
# compute minimum and maximum on the training data
scaler = MinMaxScaler().fit(X_train)
# rescale the training data
X_train_scaled = scaler.transform(X_train)
svm = SVC()
# learn an SVM on the scaled training data
svm.fit(X_train_scaled, y_train)
# scale the test data and score the scaled data
X_test_scaled = scaler.transform(X_test)
print("Test score:{:.2f}".format(svm.score(X_test_scaled, y_test)))
Test score: 0.95
一、用预处理进行参数选择
一个不易察觉的问题的例子:
from sklearn.model_selection import GridSearchCV
# for illustration purposes only, don't use this code!
param_grid = {'C': [0.001, 0.01, 0.1, 1, 10, 100],
'gamma': [0.001, 0.01, 0.1, 1, 10, 100]}
grid = GridSearchCV(SVC(), param_grid=param_grid, cv=5)
grid.fit(X_train_scaled, y_train)
print("Best cross-validation accuracy:{:.2f}".format(grid.best_score_))
print("Best parameters: ", grid.best_params_)
print("Test set accuracy:{:.2f}".format(grid.score(X_test_scaled, y_test)))
Best cross-validation accuracy: 0.98
Best parameters: {'C': 1, 'gamma': 1}
Test set accuracy: 0.97
这里我们利用缩放后的数据对SVC参数进行网格搜索。但是,上面的代码中有一个不易察觉的陷阱。在缩放数据时,我们使用了训练集中的所有数据来找到训练的方法。然后,我们使用缩放后的训练数据来运行带交叉验证的网格搜索。对于交叉验证中的每次划分,原始训练集的一部分被划分为训练部分,另一部分被划分为测试部分。测试部分用于度量在训练部分上所训练的模型在新数据上的表现。但是,我们在缩放数据时已经使用过测试部分中所包含的信息。请记住,交叉验证每次划分的测试部分都是训练集的一部分,我们使用整个训练集的信息来找到数据的正确缩放。
对于模型来说,这些数据与新数据看起来截然不同。如果我们观察新数据(比如测试集中的数据),那么这些数据并没有用于对训练数据进行缩放,其最大值和最小值也可能与训练数据不同。下面这个例子显示了交叉验证与最终评估这两个过程中数据处理的不同之处:
mglearn.plots.plot_improper_processing()
对于建模过程,交叉验证中的划分无法正确地反映新数据的特征。我们已经将这部分数据的信息泄露给建模过程。这将导致在交叉验证过程中得到过于乐观的结果,并可能会导致选择次优的参数。
为了解决这个问题,在交叉验证过程中,应该在进行任何预处理之前完成数据集的划分。任何从数据集中提取信息的处理过程都应该仅应用于数据集的训练部分,因此,任何交叉验证都应该