k-Nearest Neighbors
Introduction
K-Nearest Neighbors(KNN)是机器学习的基本分类器。 分类器采用已标记的数据集,然后尝试将新数据点标记为其中一个类别。 因此,我们试图确定对象所在的类。为此,我们查看对象的最近点(邻居),并且具有大多数邻居的类将是我们识别要进入的对象的类。 k是对象的最近邻居的数量。 因此,如果k = 1,则对象所在的类是最近邻居的类。 我们来看一个例子。
在这个例子中,我们试图将红色星分类为绿色方块或蓝色八边形。 首先,如果我们看一下k = 3的内圈,我们可以看到有2个蓝色八边形和1个绿色方块。 所以有大多数蓝色八角形,所以红色星将被归类为蓝色八角形。 现在我们看看k = 5,即外圈。 在这一个中有2个蓝色八边形和3个绿色方块。 然后,红星将被归类为绿色方块。
How does it work?
我们将研究两种不同的方法。 两种方式是强力方法和K-D树方法。
Brute Force Method
这是最简单的方法。 基本上,它只是计算从被分类的对象到集合中每个点的欧几里德距离。 欧几里德距离只是连接两个点的线段的长度。 当点的尺寸小或点数小时,蛮力方法很有用。 随着点数的增加,该方法必须计算欧几里德距离的次数也增加,因此该方法的性能下降。 幸运的是,K-D树方法更适合更大的数据集。
K-D Tree Method
该方法试图通过减少计算欧几里德距离的次数来改善运行时间。 这种方法背后的想法是,如果我们知道两个数据点彼此接近,我们计算到其中一个的欧几里德距离,然后我们知道距离大致接近另一个点。 以下是K-D树的外观示例。
K-D树的工作原理是树中的节点表示并保存来自n维图的数据。 每个节点代表图中的一个框。 首先,我们可以从一组数据中构建一个KD树,然后在分类点的时候,我们只需看一下该点落在树中的位置,然后计算它接近的点之间的欧几里德距离,直到我们 到达k个邻居。
如果您有更大的数据集,建议使用此方法。 这是因为如果数据集较大则创建K-D树的成本相对较低,并且随着数据变大,分类点的成本是恒定的。
Choosing k
选择k通常取决于您正在查看的数据集。 你永远不想选择k = 2,因为它很可能没有多数类,所以在上面的例子中会有一个,所以我们将无法对红星进行分类。 通常,您希望k的值很小。 当k变为无穷大时,所有未识别的数据点将始终被分类为一个类或另一个类,这取决于哪个类具有更多数据点。 你不希望这种情况发生,所以选择一个相对较小的k是明智的。
Conclusion
以下是一些可以拿走的东西:
1、KNN的不同方法只影响性能,而不影响输出
2、当点的尺寸或点数很小时,蛮力方法最好
3、当您拥有更大的数据集时,K-D树方法最佳
4、SKLearn KNN分类器有一个自动方法,它根据训练的数据决定使用什么方法。
选择k的值将彻底改变数据的分类方式。 较高的k值将忽略数据的异常值,较低的k值将给予它们更多的权重。 如果k值太高,则无法对数据进行分类,因此k需要相对较小。
Motivation
那么为什么有人会使用这个分类器呢? 这是最好的分类器吗? 这些问题的答案取决于它。 没有最好的分类器,它取决于给定分类器的数据。 对于一个数据集而言,KNN可能是最好的,而对另一个 了解其他分类器(例如支持向量机),然后决定哪一个对给定数据集进行最佳分类是很好的。
Code Example
查看我们的代码knn.py,了解如何使用Python的Scikit-learn库实现k最近邻分类器。 有关Scikit-Learn的更多信息,请访问此处here。
knn.py,从Scikit-Learn的数据集库中加载一组乳腺癌数据。 程序将获取数据并将其绘制在图形上,然后使用KNN算法最佳地分离数据。 输出应如下所示:
绿点被归类为良性。 红点被归类为恶性。 边界线是分类器的预测。 该边界线由k值确定,对于该实例k = 9。
这将加载Scikit-Learn数据集库中的数据。 您可以将数据更改为您想要的任何数据。 只需确保您拥有数据点和一系列目标即可对这些数据点进行分类。
您还可以更改将更改算法的k值或n_neighbors值。 建议您选择相对较小的k。
您也可以更改使用的算法,选项是{'auto','ball_tree','kd_tree','brute'}。 这些不会改变预测的输出,它们只会改变预测数据所需的时间。
尝试在下面的代码中将n_neighbors的值更改为1。
如果将n_neighbors的值更改为1,则将按最接近该点的点进行分类。 输出应如下所示:
将此输出与k = 9进行比较,您可以看到它对数据进行分类的巨大差异。 因此,如果你想忽略异常值,你会想要更高的k值,否则选择一个更小的k,如1,3或5.你可以通过选择一个大于100的非常高的k来进行实验。最后,算法会将所有数据分类为1 class,并没有用于拆分数据的行。