2.3 更复杂的数据集和更复杂的分类器
现在我们看一个复杂一点的数据集。这将推动下文对新的分类算法以及其他一些想法的介绍。
2.3.1 从 Seeds 数据集中学习
现在我们考虑另一个农业数据集;它的规模依然很小,但是要想如 Iris 数据集那样自如详尽地画出来,它的规模就显得太大了。这是一个关于小麦种子的测量数据集。下面列出了它的 7 个特征:
- 面积(A)
- 周长(P)
- 紧密度(C=4πA/P2 )
- 谷粒的长度
- 谷粒的宽度
- 偏度系数
- 谷粒槽长度
这些种子一共分为三个类别,属于小麦的三个不同品种:Canadian、Kama 和 Rosa。和以前一样,我们的目标是根据对小麦形态的测量对小麦品种进行分类。
与收集于 20 世纪 30 年代的 Iris 数据集不同,这是一个非常新的数据集,它的特征都是从数字图像上自动计算生成的。
图像模式识别是这样实现的:你得到一些数字格式的图像,从中计算出一些相关特征,然后使用一般的分类系统进行分类。在下面一章中,我们将会深入讨论计算机如何进行视觉方面的工作,并从图像中提取特征。在这一节里,我们还是先使用已经给出的特征。
提示 UCI 机器学习数据集仓库
加州大学欧文分校(UCI) 维护了一个线上机器学习数据集仓库(在本书撰写时,它一共列出了 233 个数据集)。本章使用的 Iris 和 Seeds 数据集都是从那里获得的。
该仓库可以在线上访问: http://archive.ics.uci.edu/ml/ 。
2.3.2 特征和特征工程
这些特征的一个有趣地方是,紧密度特征实际上并不是一个新的测量值,而是之前两个特征,面积和周长,所组成的函数。这个通用领域叫做特征工程 (feature engineering)。人们有时认为它没有算法那样富有魅力,但它对系统性能也许有很大的影响(一个简单算法在精心选择的特征上的效果比一个漂亮算法在较差的特征上的效果还要好)。
对这里,原作者计算了“紧密度”这个特征,这是一个典型的形状特征(也叫做“圆度”)。如果两个谷粒,一个的大小是另一个的两倍,但形状一样,那么这个特征将具有相同的值。然而,对于非常圆的谷粒(特征值接近 1)和扁长的谷粒(特征值接近 0),它的值会很不相同。
好特征的目标是在重要的地方取不同值,而在不重要的地方不变。例如,紧密度不会随大小而改变,但会随着形状而变化。在实践中,要同时完美地达到这两个目标可能很困难,但我们希望能够逼近这种理想情况。
你需要借助背景知识通过直觉来判断哪些是好特征。幸运的是,在很多问题领域,已经有很多文献介绍了可能用到的特征和特征类型。对于图像,之前提到的所有特征都是很典型的,计算机视觉库可以帮你计算出来。基于文本的问题也是如此,有很多标准的解决方案可以混合搭配。尽管,你通常可以利用特定问题中的领域知识来设计出一个特定的特征。
甚至在获取数据之前,你必须决定哪些数据值得收集。然后,你需要将所有的特征交给机器去评估和计算最优分类器。
一个很自然就会想到的问题是,我们能否自动地把好特征选取出来。这个问题叫做特征选择 (feature selection)。人们已经提出了很多方法来解决这个问题,但在实践中,极简单的想法可能已经可以做得很好。在这些小数据集上使用特征选择没有什么意义,但是如果你有几千个特征,那扔掉其中大多数特征将会大大加快后续的流程。
2.3.3 最邻近分类
对于这个数据集,即使采用之前的方法只能把两个类区分出来,而且不能得到很好的结果。因此,让我们介绍一个新的分类器:最邻近分类器。
考虑到每个样本是由它的特征所表示的(用数学语言来讲,它是N 维空间中的点),我们可以计算样本之间的距离,而且可以选择不同方法来计算这个距离,例如:
def distance(p0, p1): 'Computes squared euclidean distance' return np.sum( (p0-p1)**2)
在分类的时候,我们采用一个简单的规则:对于一个新样本,我们在数据集中寻找最接近它的点(它最近的近邻),并查看它的标签:
def nn_classify(training_set, training_labels, new_example): dists = np.array([distance(t, new_example) for t in training_set]) nearest = dists.argmin() return training_labels[nearest]
在这种情况下,我们的模型不使用任何训练数据及标签,就能在分类阶段计算出所有的结果。一个更好的实现方法是,在学习阶段对这些数据做索引,从而加速分类的计算,但这个实现是一个很复杂的算法。
现在,我们注意到这个模型在训练数据上表现得很完美。在每个数据点上,它的最近近邻就是它自己,所以它的标签一定完美匹配(除非两个样本具有相同的特征但标签不同,而这是可能发生的)。因此,采用交叉验证来进行测试是很必要的。
我们在这个数据集上应用这个算法,并进行 10 折交叉验证,可以得到 88%的正确率。正如之前几节中讨论的,交叉验证正确率会低于训练正确率,但这是对模型性能更可靠的估计。
我们现在来看一下判别边界。对此,我们必须简化一下,只考虑两个维度(这样我们就可以把它画在纸上了)。
在前图中,Canadian 样本是用菱形表示的,Kama 种子是用圆圈表示的,Rosa 种子是用三角形表示的。它们的区域分别用白色、黑色和灰色表示。你可能会对为何这些区域都是水平方向的感到疑惑,觉得这非常古怪。这里的问题在于,x 轴(面积)的值域在 10 到 22 之间,而y 轴(紧密度)在 0.75 到 1.0 之间。这意味着,x 值的一小点改变实际上比y 值的一小点变化大得多。所以,在用之前的函数计算距离的时候,我们多半只把x 轴考虑进去了。
如果你了解一些物理学背景知识,你可能已经注意到我们已经把长度、面积和无量纲的量加了起来,把各种单位混合在一起了(我们从不会在物理系统中这样做)。我们需要把所有特征都归一化到一个公共尺度上。这个问题有很多解决方法;一个简单的方法是把它们归一到Z 值(Z-score)。Z 值表示的是特征值离它的平均值有多远,它用标准方差的数量来计算。它可以归结到以下这一对简单的操作上:
# 从特征值中减去特征的平均值 features -= features.mean(axis=0) # 将特征值除以它的标准差 features /= features.std(axis=0)
转换为Z 值之后,0 就是平均值,正数是高于平均值的值,负数是低于平均值的值,它独立于原始值。
现在每个特征都采用了同样的单位(严格来说,每个特征现在都是无量纲的,它没有单位),因此我们可以更放心地混合不同维度的特征。事实上,如果现在运行最邻近分类器,我们可以得到 94%的正确率!
再次看看这两个维度的决策空间,它如下图所示:
分界面变得非常复杂,而且在两个维度之间有一个相互交叉。如果使用数据全集,那么所有这些都发生在七维空间中,它非常难以可视化地显示出来。但是道理是一样的:之前是少数维度占据统治地位,而现在所有维度都具有相同的重要性。
最邻近分类器虽然很简单,但有时它的效果已经足够好。我们可以把它泛化成一个 k 邻近 分类器,不仅考虑最邻近的点,还要考虑前k 个最邻近点。所有这k 个邻近点通过投票方式来选择标签。k 一般是一个小数字,比如 5,但它也可以更大,特别是当数据规模非常大的时候。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论