K Nearest Neighbor算法又叫KNN算法。如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。
为了度量空间中点的距离,有许多方式,最常见的三种方式就是欧氏距离,曼哈顿距离以及切比雪夫距离。
欧氏距离是最容易直观理解的距离度量方法,通常KNN算法中使用的是欧式距离。 二维平面上点 a ( x 1 , y 1 ) \mathrm{a}\left(\mathrm{x}_{1}, \mathrm{y}_{1}\right) a(x1,y1) 与b ( x 2 , y 2 ) \left(\mathrm{x}_{2}, \mathrm{y}_{2}\right) (x2,y2) 间的欧氏距离: d 12 = ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 \quad d_{12}=\sqrt{\left(x_{1}-x_{2}\right)^{2}+\left(y_{1}-y_{2}\right)^{2}} d12=(x1−x2)2+(y1−y2)2 三维空间点a ( x 1 , y 1 , z 1 ) \left(\mathrm{x}_{1}, \mathrm{y}_{1}, \mathrm{z}_{1}\right) (x1,y1,z1) 与 b ( x 2 , y 2 , z 2 ) \mathrm{b}\left(\mathrm{x}_{2}, \mathrm{y}_{2}, \mathrm{z}_{2}\right) b(x2,y2,z2) 间的欧氏距离: d 12 = ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 + ( z 1 − z 2 ) 2 d_{12}=\sqrt{\left(x_{1}-x_{2}\right)^{2}+\left(y_{1}-y_{2}\right)^{2}+\left(z_{1}-z_{2}\right)^{2}} d12=(x1−x2)2+(y1−y2)2+(z1−z2)2 n维空间点a ( x 11 , x 12 , … , x 1 n ) 吻 ( x 21 , x 22 , … , x 2 n ) \left(\mathrm{x}_{11}, \mathrm{x}_{12}, \ldots, \mathrm{x}_{1 n}\right) 吻\left(\mathrm{x}_{21}, \mathrm{x}_{22}, \ldots, \mathrm{x}_{2 n}\right) (x11,x12,…,x1n)吻(x21,x22,…,x2n) 间的欧氏距离 ( 两个n维向量 ) : d 12 = ∑ k = 1 n ( x 1 k − x 2 k ) 2 d_{12}=\sqrt{\sum_{k=1}^{n}\left(x_{1 k}-x_{2 k}\right)^{2}} d12=k=1∑n(x1k−x2k)2
在曼哈顿街区要从一个十字路口开车到另一个十字路口, 驾驶距离显然不是两点间的直线距离。这个实际驾驶距离就是"曼哈顿距离”。曼哈顿距离也称为“城市街区距离"(City Block distance)
二维平面两点 a ( x 1 , y 1 ) a\left(x_{1}, y_{1}\right) a(x1,y1) 与 b ( x 2 , y 2 ) b\left(x_{2}, y_{2}\right) b(x2,y2) 间的曼哈顿距离: d 12 = ∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ \quad d_{12}=\left|x_{1}-x_{2}\right|+\left|y_{1}-y_{2}\right| d12=∣x1−x2∣+∣y1−y2∣ n维平面两点 a ( x 11 , x 12 , … , x 1 n ) a\left(x_{11},x_{12},…, x_{1n}\right) a(x11,x12,…,x1n) 与 b ( x 21 , x 22 , … , x 2 n ) b\left(x_{21},x_{22},…, x_{2n}\right) b(x21,x22,…,x2n) 间的曼哈顿距离: d 12 = ∑ k = 1 n ∣ x 1 k − x 2 k ∣ d_{12}=\sum_{k=1}^{n}\left|x_{1 k}-x_{2 k}\right| d12=k=1∑n∣x1k−x2k∣
国际象棋中, 国王可以直行、横行、斜行, 所以国王走一步可以移动到相邻8个方格中的任意一个。国王从 格子(x1,y1)走到格子(x2,y2)最少需要多少步? 这个距离就口切比雪夫距离。
二维平面两点 a ( x 1 , y 1 ) a\left(x_{1}, y_{1}\right) a(x1,y1) 与 b ( x 2 , y 2 ) b\left(x_{2}, y_{2}\right) b(x2,y2) 间的切比雪夫距离: d 12 = max ( ∣ x 1 − x 2 ∣ , ∣ y 1 − y 2 ∣ ) \quad d_{12}=\max \left(\left|x_{1}-x_{2}\right|,\left|y_{1}-y_{2}\right|\right) d12=max(∣x1−x2∣,∣y1−y2∣) n维空间点 a ( x 1 ∣ , x 1 , … , x 10 ) a\left(x_{1} \mid, x_{1}, \ldots, x_{10}\right) a(x1∣,x1,…,x10) 与 b ( x 2 , x 2 , … , x 2 ) b\left(x_{2}, x_{2}, \ldots, x_{2}\right) b(x2,x2,…,x2) 的切比雪夫距离 d 12 = max ( ∣ x 1 i − x 2 i ∣ ) d_{12}=\max \left(\left|x_{1 i}-x_{2 i}\right|\right) d12=max(∣x1i−x2i∣)
「统计学习方法」上所说:
选择较小的K值,就相当于用较小的领域中的训练实例进行预测,“学习”近似误差会减小,只有与输入实例较近或相似的训练实例才会对预测结果起作用,与此同时带来的问题是“学习”的估计误差会增大,换句话说,K值的减小就意味着整体模型变得复杂,容易发生过拟合;
选择较大的K值,就相当于用较大领域中的训练实例进行预测,其优点是可以减少学习的估计误差,但缺点是学习的近似误差会增大。这时候,与输入实例较远(不相似的)训练实例也会对预测器作用,使预测发生错误,且K值的增大就意味着整体的模型变得简单。
K=N(N为训练样本个数),则完全不足取,因为此时无论输入实例是什么,都只是简单的预测它属于在训练实例中最多的类,模型过于简单,忽略了训练实例中大量有用信息。
在实际应用中,K值一般取一个比较小的数值,例如采用交叉验证法(简单来说,就是把训练数据在分成两组:训练集和验证集)来选择最优的K值。对这个简单的分类器进行泛化,用核方法把这个线性模型扩展到非线性的情况,具体方法是把低维数据集映射到高维特征空间。
实现k近邻法时,主要考虑的问题是如何对训练数据进行快速k近邻搜索。这在特征空间的维数大及训练数据容量大时尤其必要。
k近邻法最简单的实现是线性扫描(穷举搜索),即要计算输入实例与每一个训练实例的距离。计算并存储好以后,再查找K近邻。当数据集很大时,这个计算成本非常高,针对N个样本,D个特征的数据集,其算法复杂度为 O ( D N 2 ) O(DN^2) O(DN2)。
为了提高kNN搜索的效率,可以考虑使用特殊的结构存储训练数据,以减小计算距离的次数。
kd树为了避免每次都重新计算一遍距离,算法会把距离信息保存在一棵树里,这样在计算之前从树里查询距离信息,尽量避免重新计算。其基本原理是,如果A和B距离很远,B和C距离很近,那么A和C的距离也很远。有了这个信息,就可以在合适的时候跳过距离远的点。
这样优化后的算法复杂度可降低到 O ( D N l o g ( N ) ) O(DNlog(N)) O(DNlog(N))。
(1)构造根结点,使根结点对应于K维空间中包含所有实例点的超矩形区域;
(2)通过递归的方法,不断地对k维空间进行切分,生成子结点。在超矩形区域上选择一个坐标轴和在此坐标轴上的一个切分点,确定一个超平面,这个超平面通过选定的切分点并垂直于选定的坐标轴,将当前超矩形区域切分为左右两个子区域(子结点);这时,实例被分到两个子区域。
(3)上述过程直到子区域内没有实例时终止(终止时的结点为叶结点)。在此过程中,将实例保存在相应的结点上。
(4)通常,循环的选择坐标轴对空间切分,选择训练实例点在坐标轴上的中位数为切分点,这样得到的kd树是平衡的(平衡二叉树:它是一棵空树,或其左子树和右子树的深度之差的绝对值不超过1,且它的左子树和右子树都是平衡二叉树)。
KD树中每个节点是一个向量,和二叉树按照数的大小划分不同的是,KD树每层需要选定向量中的某一维,然后根据这一维按左小右大的方式划分数据。在构建KD树时,关键需要解决2个问题:
(1)选择向量的哪一维进行划分;
(2)如何划分数据;
第一个问题简单的解决方法可以是随机选择某一维或按顺序选择,但是更好的方法应该是在数据比较分散的那一维进行划分(分散的程度可以根据方差来衡量)。好的划分方法可以使构建的树比较平衡,可以每次选择中位数来进行划分,这样问题2也得到了解决。