基于KD树的K近邻算法(KNN)算法

文章目录

  • KNN 简介
  • KNN 三要素
    • 距离度量
    • k值的选择
    • 分类决策规则
  • KNN 实现
    • 1,构造kd树
    • 2,搜索最近邻
    • 3,预测
  • 用kd树完成最近邻搜索

K近邻算法(KNN)算法,是一种基本的分类与回归算法,本文只讨论解决分类问题的KNN算法。

KNN 简介

思想:给定一个训练数据集,对于新输入的样本,在训练集中找到与该样本最邻近的k个已知样本,这k个已知样本的多数属于某个类别,那么新输入的样本就属于这个类别。

如下图所示,假定使用欧氏距离作为度量方式,采样投票法决定类别,并且?表示待预测的样本,当k取1时,则变成了最近邻算法,对应的类别为★;当k取7时,类别为▲;可见k的取值对分类效果有比较大的影响。在实际应用中,k的取值一般不超过20。

基于KD树的K近邻算法(KNN)算法_第1张图片

该算法的优点是:

  1. 精度高
  2. 对异常值不敏感
  3. 无数据输入假定

缺点是:

  1. 计算复杂度高
  2. 空间复杂度高

KNN 三要素

KNN算法不具有显式的训练过程。距离度量(如欧氏距离)、k值以及分类决策规则(如投票表决)是KNN算法的三要素。在给定训练集合于三要素后,对于任何新输入的样本,它所属的类别是唯一确定的。下面对这三个要素展开讨论。

距离度量

在n维的特征空间中,距离反映的是两个点的相似程度。KNN 算法常用的距离度量为欧式距离,但也可以采用其他距离,比如更一般的 L p L_{p} Lp距离,其中p为正整数:
L p ( x i , x j ) = ( ∑ l = 1 n ∣ x i ( l ) − x j ( l ) ∣ p ) 1 p L_p(x_i, x_j)=\left(\sum_{l=1}^{n}{\left|x_{i}^{(l)}-x_{j}^{(l)}\right|^p}\right)^{\frac{1}{p}} Lp(xi,xj)=(l=1nxi(l)xj(l)p)p1
当p=1时,即为曼哈顿距离,也叫出租车距离,用以标明两个点在标准坐标系上的绝对轴距总和,如下图中的红色线条所示,蓝色和黄色为等价曼哈顿距离。

基于KD树的K近邻算法(KNN)算法_第2张图片

当p=2时,即为常见的欧氏距离,也就是直线距离,如上图的绿色线条所示。

不同距离度量确定的最近点是不同的,例如对于:
x 1 = ( 1 , 1 ) , x 2 = ( 5 , 1 ) , x 3 = ( 4 , 4 ) x_1=(1, 1), x_2 = (5,1), x_3 = (4,4) x1=(1,1),x2=(5,1),x3=(4,4)
由于 x 1 , x 2 x_1, x_2 x1,x2只有一个坐标轴不同,所以无论p取多少,距离都为4。但是:
L 1 ( x 1 , x 3 ) = 6 , L 2 ( x 1 , x 3 ) = 4.24 L 3 ( x 1 , x 3 ) = 3.78 , L 4 ( x 1 , x 3 ) = 3.57 L_1(x_1, x_3)=6, L_2(x_1, x_3)=4.24\\ L_3(x_1, x_3)=3.78, L_4(x_1, x_3)=3.57 L1(x1,x3)=6,L2(x1,x3)=4.24L3(x1,x3)=3.78,L4(x1,x3)=3.57
也就是说当p大于等于3时, x 1 , x 3 x_1, x_3 x1,x3 之间距离最近。

k值的选择

k 值的选择对结果会产生重大影响。

如果选择较小的k值,那么相当于只用少数的训练样本完成预测。这样的预测结果对邻近的样本点非常敏感,一方面容易造成过拟合,另一方面容易受到恰巧是噪声的临近点的干扰。

如果选择较大的k值,那么距离较远的(不相似)的点也会对预测结果产生影响,容易使得预测结果发生错误。极端情况下,当k取样本的个数时,预测结果就是众数,完全忽略了训练样本中真正有效的信息。

实际应用中,k一般取较小的值,采用交叉验证的方法确定最优的k值。

分类决策规则

一般是以多数表决为决策规则,即通过投票决定最终的类别。

假设分类函数为:
f : R n → { c 1 , c 2 , . . . , c K } f: R^n \rightarrow\{c_1, c_2,..., c_K\} f:Rn{c1,c2,...,cK}
对一个预测结果 f ( X ) f(X) f(X)而言,误分类的概率为:
P ( Y ≠ f ( X ) ) = 1 − P ( Y = f ( X ) ) P(Y \ne f(X)) = 1-P(Y=f(X)) P(Y=f(X))=1P(Y=f(X))
假定KNN取最近邻的k个样本组成的集合 N k ( x ) N_k(x) Nk(x)用于表决,设表决结果为 c j c_j cj,那么误分类的概率为:
1 k ∑ x i ∈ N k ( x ) I ( y i ≠ c i ) = 1 − 1 k ∑ x i ∈ N k ( x ) I ( y i = c i ) \frac{1}{k}\sum_{x_i\in N_k(x)}{I(y_i\ne c_i)}=1-\frac{1}{k}\sum_{x_i\in N_k(x)}{I(y_i= c_i)} k1xiNk(x)I(yi=ci)=1k1xiNk(x)I(yi=ci)
要使得误分类概率最小,则需要 1 k ∑ x i ∈ N k ( x ) I ( y i = c i ) \frac{1}{k}\sum_{x_i\in N_k(x)}{I(y_i= c_i)} k1xiNk(x)I(yi=ci)最大,也就是 c j c_j cj 应该是 N k ( x ) N_k(x) Nk(x)中出现次数最多的类别。

KNN 实现

实现KNN算法时,主要问题是如何快速在训练样本中找到k个最近邻的点。

一种最简单的实现是线性扫描,每输入一个新的样本,就需要计算这个样本和所有训练样本的距离,进而找到最近的k个样本。这样计算过于耗时,在特征空间维数很高以及训练样本特别多时尤为明显。

为了提高搜索效率,可以考虑使用树来存储训练数据,例如使用kd树算法。kd树中的k表示存储k维空间数据的树结构,与KNN中的k意义不同。

kd树算法包括三个步骤:1,构造kd树。2,搜索最近邻。3,预测。

1,构造kd树

kd树是二叉树,表示对k维空间的一个划分。构造kd树的过程就是不断的用垂直于坐标轴的超平面来切分k维空间,构成一些列的k维超矩形区域。最终kd树的每一个节点对应于一个k维超矩形区域。

具体而言,KD树建树首先计算m个样本的n个特征的取值的方差,用方差最大的第k维特征 n k n_k nk来作为根节点。假设特征 n k n_k nk的中位数为 n k v n_{kv} nkv,那么对于所有第k维特征的取值小于 n k v n_{kv} nkv的样本,我们划入左子树,对于第k维特征的取值大于等于 n k v n_{kv} nkv的样本,我们划入右子树。对于左右两颗子树,则对未用于父节点划分的特征重复上面的操作,直到左右子树没有样本时终止。

举个例子,假设有二维样本6个,{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},构建kd树的具体步骤为:

(1) 找到划分特征。x维度方差6.97 > y维度方差 5.37。所以选择第一个维度进行划分。

(2) 确定划分点。x维度数字为:2,4,5,7,8,9。可以取中位数为:5或者7,这里取7。于是划分超平面会经过(7,2)且垂直于坐标轴X。

(3) 确定左右子空间。由于划分超平面的确定,所以x<=7的样本{(2,3),(5,4),(4,7)}属于左子空间,x>=7的样本{(9,6),(8,1)}属于右子空间。

(3) 对未用于父节点划分的特征重复上面的操作。

最后得到的KD树如下:
基于KD树的K近邻算法(KNN)算法_第3张图片

基于KD树的K近邻算法(KNN)算法_第4张图片

2,搜索最近邻

给定目标点(2,4.5),要搜索其最近邻,首先要找到包含目标点的叶节点。具体而言,首先从根节点(7,2)出发,首先根据x=2 < x=7向左找到节点(5,4),继续跟进y=4.5 > y=4 向右找到(4,7),即与目标点最近的点为(4,7)。

以目标点(2,4.5)为圆心,以目标点到叶子节点(4,7)样本实例的距离3.202为半径,得到一个超球体。最近邻的点肯定在超球体的内部,如下图所示:

基于KD树的K近邻算法(KNN)算法_第5张图片

计算得到圆心到其父节点(5,4)的距离为3.041,所以最近邻点更新为(5, 4)。

继续查找在半径3.041内的点,发现父节点(5,4)的另一边的子空间和超球面有交集,所以还需要到(5,4)的左子空间内确定其中的点到目标点的距离是否更小。发现(2,3)节点的距离更小,最近邻点更新为(2,3),最近距离更新为1.5。

此时目标点区域父节点(5,4)的两个子空间都搜索完毕,需要继续搜索(5,4)的父节点的另一个子空间是否有更近的点。重复这个过程,直到遇到根节点后结束搜索,得到最近邻的点为(2,3)。

上面的过程总结如下:

当我们生成KD树以后,就可以去预测测试集里面的样本目标点了。对于一个目标点,我们首先在KD树里面找到包含目标点的叶子节点。以目标点为圆心,以目标点到叶子节点样本实例的距离为半径,得到一个超球体,最近邻的点一定在这个超球体内部。然后返回叶子节点的父节点,检查另一个子节点包含的超矩形体是否和超球体相交,如果相交就到这个子节点寻找是否有更加近的近邻,有的话就更新最近邻。如果不相交那就简单了,我们直接返回父节点的父节点,在另一个子树继续搜索最近邻。当回溯到根节点时,算法结束,此时保存的最近邻节点就是最终的最近邻。

3,预测

理解最近邻点的搜索方法后,如果我们要查找最近邻的K个点,只需要在第一轮先找到最近邻点,然后在第二轮忽略这个最近邻的点,查找次最近邻的点。重复这个过程,直到找到了K个近邻的点。如果是KNN分类,预测为K个最近邻里面有最多类别数的类别。如果是KNN回归,用K个最近邻样本输出的平均值作为回归预测值。

用kd树完成最近邻搜索

输入:已构造的kd树,目标点x

输出: x的最近邻。

(1) 在kd树中找出包含目标点x的叶结点:从根结点出发,递归地向下访问kd树。若目标点x当前维的坐标小于切分点的坐标,则移动到左子结点,否则移动到右子结点。直到子结点为叶结点为止。.

(2) 以找到的叶结点为“当前最近点”。

(3) 递归地向上回退,在每个父结点进行以下操作:

  1. 如果该结点保存的实例点比当前最近点距离目标点更近,则以该实例点为“当前最近点”。

  2. 当前最近点一定存在于该父结点的一个子结点对应的区域,即检查父结点的另一子结点对应的区域是否有更近的点。具体地,检查另一子结点对应的区域是否与以目标点为球心、以目标点与“当前最近点”间的距离为半径的超球体相交。

    如果相交,可能在另一个子结点对应的区域内存在距目标点更近的点,移动到另一个子结点。接着,递归地进行最近邻搜索。

    如果不相交,向上回退。

(4) 当回退到根结点时,搜索结束。最后的“当前最近点”即为x的最近邻点。

如果实例点是随机分布的,kd树搜索的平均计算复杂度是O(logN),这里N是训练实例数。kd树更适用于训练实例数远大于空间维数时的k近邻搜索。当空间维数接近训练实例数时,它的效率会迅速下降,几乎接近线性扫描。

参考文章:

《统计学习方法 第二版》

K近邻法(KNN)原理小结

你可能感兴趣的:(机器学习基础)