管道模型Pipeline《Python机器学习》之十九

1.导入

前面有过这样的例子,首先对数据进行缩放,然后手动合并特征,再利用无监督机器学习来学习特征。因此,大多数机器学习应用不仅需要应用单个算法,而且还需要将许多不同的处理步骤和机器学习模型链接在一起。接下来将介绍如何使用Pipeline 类来简化构建变换和模型链的过程,将重点介绍如何将Pipeline 和GridSearchCV 结合起来,从而同时搜索所有处理步骤中的参数。

举一个例子来说明模型链的重要性。我们知道,可以通过使用MinMaxScaler 进行预处理来大大提高核SVM 在cancer 数据集上的性能。下面这些代码实现了划分数据、计算最小值和最大值、缩放数据与训练SVM:

上面的代码第11行,是在x_train数据中找到最大值、最小值,然后用它分别缩放训练集和测试集,如第13、15行所示。这是所要求的正确的做法。

现看下面的例子:训练集和验证集却没有遵循这个要求。

!!! 问题所在 : 交叉验证的数据集是已经在外面进行缩放处理的训练集,在交叉验证内部将其分外 训练集和验证集如图 6-1所示。

谨记一条原则:先划分数据集,再进行缩放处理或其它预处理。

那么,在交叉验证内部,如何做到呢?

在scikit-learn 中,要想使用cross_val_score 函数和GridSearchCV 函数实现这一点,可以使用Pipeline 类。Pipeline 类可以将多个处理步骤合并(glue)为单个scikit-learn 估计器。Pipeline 类本身具有fit、predict 和score 方法,其行为与scikit-learn 中的其他模型相同。Pipeline 类最常见的用例是将预处理步骤(比如数据缩放)与一个监督模型(比如分类器)链接在一起。2.构建管道的方法

我们来看一下如何使用Pipeline 类来表示在使用MinMaxScaler 缩放数据之后再训练一个SVM 的工作流程(对应本文开头的第一个例子)。首先,我们构建一个由步骤列表组成的管道对象。每个步骤都是一个元组,其中包含一个名称和一个估计器的实例。

这里创建了两个步骤:第一个叫作"scaler",是MinMaxScaler 的实例;第二个叫作"svm",是SVC 的实例。现在来拟合这个管道,pipe.fit 首先对第一个步骤(缩放器)调用fit,然后使用该缩放器对训练数据进行变换,最后用缩放后的数据来拟合SVM。要想在测试数据上进行评估,我们只需调用pipe.score,代码如下:

在对管道调用score 方法时,首先使用缩放器对测试数据进行变换,然后利用缩放后的测试数据对SVM 调用score 方法。如你所见,这个结果与我们从本章开头的第一个例子中的代码得到的结果是相同的。利用管道,我们减少了“预处理+ 分类”过程所需要的代码量。

使用管道的主要优点在于,现在我们可以在cross_val_score 或GridSearchCV 中使用这个估计器,针对本文开头的第二例子使用管道:3.解决问题:在网络搜索中使用管道

我们定义一个需要搜索的参数网格,并利用管道和参数网格构建一个GridSearchCV。不过在指定参数网格时存在一处细微的变化。我们需要为每个参数指定它在管道中所属的步骤。我们要调节的两个参数C 和gamma 都是SVC 的参数,属于第二个步骤。我们给这个步骤的名称是"svm"。为管道定义参数网格的语法是为每个参数指定步骤名称,后面加上__(双下划线),然后是参数名称。因此,要想搜索SVC 的C 参数,必须使用"svm__C" 作为参数网格字典的键,对gamma 参数也是同理:

与本文开头的第二例子中所做的网格搜索不同,现在对于交叉验证的每次划分来说,仅使用训练部分对MinMaxScaler 进行拟合。将图6-2 与图6-1 进行对比。

图6-2: 使用管道在交叉验证循环内部进行预处理时的数据使用情况4.简析管道的工作流程

Pipeline 类不但可用于预处理和分类,实际上还可以将任意数量的估计器连接在一起。例如,你可以构建一个包含特征提取、特征选择、缩放和分类的管道,总共有4 个步骤。同样,最后一步可以是回归或聚类等。

对于管道中估计器的唯一要求就是,除了最后一步之外的所有步骤都需要具有transform方法,这样它们可以生成新的数据表示,以供下一个步骤使用。在调用Pipeline.fit 的过程中,管道内部依次对每个步骤调用fit 和transform,其输入是前一个步骤中transform 方法的输出。对于管道中的最后一步,则仅调用fit。

忽略某些细枝末节,其实现方法如下所示。请记住,pipeline.steps 是由元组组成的列表,所以pipeline.steps[0][1] 是第一个估计器,pipeline.steps[1][1] 是第二个估计器,以此类推:

4.1 用make_pipline方法创建管道¶

我们通常不需要为每一个步骤提供用户指定的名称。有一个很方便的函数make_pipeline,可以创建管道并根据每个步骤所属的类为其自动命名。make_pipeline 的语法如下所示:

4.2 访问步骤属性

通常来说,想访问管道中的步骤,最简单的方法是通过named_steps 属性,它是一个字典,将步骤名称映射为估计器:

4.3 访问网格搜索管道中的属性

使用管道的主要场景就是进行网格搜索。一个常见的任务是在网格搜索内访问管道的某些步骤。我们对cancer 数据集上的LogisticRegression 分类器进行网格搜索,在将数据传入LogisticRegression 分类器之前,先用Pipeline 和StandardScaler对数据进行缩放。首先,我们用make_pipeline 函数创建一个管道:

5. 应用举例一:网格搜索预处理步骤与模型参数

我们可以利用管道将机器学习工作流程中的所有处理步骤封装成一个scikit-learn 估计器。这么做的另一个好处在于,现在我们可以使用监督任务(比如回归或分类)的输出来调节预处理参数。在应用岭回归之前使用boston 数据集的多项式特征,下面我们用一个管道来重复这个建模过程,管道包含3 个步骤:缩放数据、计算多项式特征与岭回归:

我们怎么知道选择几次多项式,或者是否选择多项式或交互项呢?理想情况下,我们希望根据分类结果来选择degree 参数。我们可以利用管道搜索degree 参数以及Ridge 的alpha参数。为了做到这一点,我们要定义一个包含这两个参数的param_grid,并用步骤名称作为前缀:

从交叉验证的结果中可以看出,使用二次多项式很有用,但三次多项式的效果比一次或二次都要差很多。从找到的最佳参数中也可以看出这一点:

正与我们观察图6-4 中的网格搜索结果所预料的那样,不使用多项式特征得到了明显更差的结果。

同时搜索预处理参数与模型参数是一个非常强大的策略。但是要记住,GridSearchCV 会尝试指定参数的所有可能组合。因此,向网格中添加更多参数,需要构建的模型数量将呈指数增长。6.应用举例二:网格搜索选择使用哪个模型

进一步将GridSearchCV 和Pipeline 结合起来:搜索管道中正在执行的实际步骤。下面是一个例子:在iris 数据集上比较RandomForestClassifier 和SVC。我们知道,SVC需要对数据进行缩放,使用StandardScaler。RandomForestClassifier 不需要预处理。先定义管道,显式地对步骤命名。我们需要两个步骤,一个用于预处理,然后是一个分类器。我们可以用SVC 和StandardScaler 来将其实例化:

定义需要搜索的parameter_grid。我们希望classifier 是RandomForestClassifier或SVC。由于这两种分类器需要调节不同的参数,并且需要不同的预处理,所以使用搜索网格列表。为了将一个估计器分配给一个步骤,使用步骤名称作为参数名称。如果我们想跳过管道中的某个步骤(例如,RandomForest 不需要预处理),则可以将该步骤设置为None:

网格搜索的结果是SVC 与StandardScaler 预处理,在C=10 和gamma=0.01 时给出最佳结果。7.小结

Pipeline 类是一种通用工具,可以将机器学习工作流程中的多个处理步骤链接在一起。使用管道可以将多个步骤封装为单个Python 对象,这个对象具有我们熟悉的scikit-learn 接口fit、predict 和transform。特别是使用交叉验证进行模型评估与使用网格搜索进行参数选择时,使用Pipeline 类来包括所有处理步骤对正确的评估至关重要。

利用Pipeline 类还可以让代码更加简洁,并减少不用pipeline 类构建处理链时可能会犯的错误(比如忘记将所有变换器应用于测试集,或者应用顺序错误)的可能性。选择特征提取、预处理和模型的正确组合,这在某种程度上是一门艺术,通常需要一些试错。但是有了管道,这种“尝试”多个不同的处理步骤是非常简单的。在进行试验时,要小心不要将处理过程复杂化,并且一定要评估一下模型中的每个组件是否必要。

全文完

发表评论
留言与评论(共有 0 条评论)
   
验证码:

相关文章

推荐文章

'); })();