Python机器学习(原书第3版)
上QQ阅读APP看书,第一时间看更新

3.2 了解scikit-learn的第一步——训练感知器

在第2章中,我们学习了感知器规则和Adaline两个机器学习分类算法,并亲手用Python和NumPy实现了代码。现在我们来看一下scikit-learn的API,如前所述,它结合了对用户友好的界面和高度优化的几种分类算法。scikit-learn软件库不仅提供了大量的学习算法,同时也包含了预处理数据、微调和评估模型等许多方便的功能。在第4章和第5章中,我们将对此及其他基本概念进行更详细的讨论。

作为理解scikit-learn软件库的起点,本章将训练类似在第2章中实现的那种感知器。为了简单起见,本书将在以后章节中继续使用已经熟悉的鸢尾花数据集。这么做很方便,因为该数据集简单且常见,经常被用于测试和检验算法,况且我们已经在前面使用scikit-learn软件库的过程中获得了该数据集。下面将用鸢尾花数据集的两个特征来实现可视化。

我们将把150个鸢尾花样本的花瓣长度和宽度存入特征矩阵X,把相应的品种分类标签存入向量y

051-01

np.unique(y)函数把返回的三个独立分类标签存储在iris.target,以整数(012)分别存储鸢尾花Iris-setosaIris-versicolorIris-virginica的标签。虽然许多scikit-learn函数和分类方法也能处理字符串形式的分类标签,但是推荐采用整数标签,这样不但可以避免技术故障,还能因为所占内存更小而提高模型的计算性能。此外,用整数编码分类标签在大多数机器学习库中都司空见惯。

为了评估经过训练的模型对未知数据处理的效果,我们再进一步将数据集分割成单独的训练数据集和测试数据集。在第6章中,我们将围绕评估模型的最佳实践进行更详细的讨论:

051-02

利用scikit-learn库model_selection模块的train_test_split函数,把Xy数组随机拆分为30%的测试数据集(45个样本)和70%的训练数据集(105个样本)。

请注意,train_test_split函数在分割数据集之前已经在内部对训练数据集进行了洗牌,否则,所有分类标签为01的样本都会被分到训练数据集,所有分类标签为2的45份样本数据都将被分到测试数据集。通过设置random_state参数,我们将为内部的伪随机数生成器提供一个固定的随机种子(random_state=1),该生成器用于在分割数据集之前进行洗牌。采用这样固定的random_state可以确保结果可重现。

最后,我们通过定义stratify=y获得内置的分层支持。这种分层意味着调用train_test_split方法可以返回与输入数据集的分类标签相同比例的训练数据集和测试数据集。可以调用NumPy的bincount函数统计数组中每个值出现数,以验证数据:

051-03

许多机器学习和优化算法也需要进行特征缩放以获得最佳性能,正如在第2章的梯度下降示例中所看到的那样。在这里,使用scikit-learn的preprocessing模块的StandardScaler类来标准化特征:

052-01

利用前面的代码,我们可以加载preprocessing模块中的StandardScaler类,初始化一个新的StandardScaler对象,然后将其分配给变量sc。调用StandardScalerfit方法对训练数据的每个特征维度估计参数μ(样本均值)和σ(标准差)进行估算。然后再调用transform方法,利用估计的参数μ和σ标准化训练数据。在标准化测试数据集时,要注意使用相同的缩放参数以确保训练数据集与测试数据集的数值具有可比性。

完成训练数据的标准化之后,我们可以动手训练感知器模型。通过调用一对其余(OvR)方法,scikit-learn中的大多数算法都默认支持多类分类,允许把三类花的数据同时提交给感知器。具体的代码实现如下:

052-02

scikit-learn界面会让我们想起第2章中的感知器实现:从linear_model模块加载Perceptron类之后,初始化新的Perceptron对象,然后调用fit方法对模型进行训练。在这里,模型参数eta0相当于前面感知器实现中用到的学习速率etan_iter参数定义了遍历训练数据集的迭代次数。

记得在第2章中讨论过,要找到合适的学习速率需要一些试验。学习速率过大,算法会错过全局的最小代价点。学习速率过小,算法需要经过太多的迭代才会收敛,降低了学习速度,这对大型数据集的影响尤为明显。同时,我们在每次迭代后,对训练数据集用random_state参数进行洗牌,以确保初始结果可以重现。

用scikit-learn训练完模型后,我们可以调用predit方法做预测,就像在第2章中感知器实现那样,具体代码如下:

052-03

执行代码后,可以看到感知器在处理45个花朵样本时出现过1次错误分类。因此,测试数据集上的分类错误率大约为0.022或2.2%(1/45≈0.022)。

008-01

分类错误率与准确率

许多机器学习实践者报告模型的分类准确率,而不是分类错误率,两者之间的关系简单计算如下:

1-错误率=0.978或者97.8%

采用分类错误率还是准确率纯粹属于个人喜好。

scikit-learn也实现了许多不同的性能指标,我们可以通过metrics模块来调用。例如,可以计算测试数据集上感知器的分类准确率如下:

053-01

这里y_test是真分类标签,而y_pred是先前预测的分类标签。另外,每个scikit-learn分类器都有一个评分方法,可以通过综合调用predictaccuracy_score计算出分类器的预测准确率:

053-02

008-01

过拟合

注意,我们将根据本章的测试数据集来评估模型的性能。在第6章中,你将学到包括图分析在内的有用技术,如用来检测和防止过拟合的学习曲线。过拟合意味着虽然模型可以捕捉训练数据中的模式,但却不能很好地泛化未见过的新数据,我们在本章的后续部分将详细讨论。

最后,可以利用第2章中的plot_decision_regions函数绘制新训练的感知器模型的决策区,并以可视化的方式展示区分不同花朵样本的效果。但是,略加修改通过圆圈来突出显示来自测试数据集的样本:

053-03
054-01

通过小幅修改plot_decision_regions函数,我们可以在结果图上定义样本的标记索引。代码如下:

054-02

正如从结果图上所看到的那样,三类花不能被线性决策边界完全分离,如图3-1所示。

054-03

图 3-1

第2章曾讨论过感知器算法从不收敛于不完全线性可分离的数据集,这就是为什么在实践中通常不推荐使用感知器算法。下面的章节将研究更强大的可以收敛到代价最小值的线性分类器,即使这些类不是完全线性可分的。

008-01

其他的感知器参数设置

Perceptron以及其他scikit-learn函数和类通常会有一些我们不清楚的额外参数。可以通过Python的help函数(例如help(Perceptron))阅读更多关于这些参数的描述。或者学习杰出的scikit-learn在线文档(http://scikit-learn.org/stable/)。