Machine Learning(一)KNN算法


前言

k k k近邻法是一种基本的分类方法。 k k k近邻法的输入为实例的特征向量,对应于特征空间的点;输出为实例的类别。 k k k近邻法实际上利用训练数据集对特征向量空间进行划分,并作为其分类的“模型”,所以说不具有显示的学习过程。 k k k值得选择、距离度量及分类决策规则是 k k k近邻法得三个基本要素。


一、 k k k近邻算法

输入:训练数据集
T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , ⋯   , ( x N , y N ) } T =\{(x_1,y_1),(x_2,y_2),\cdots,(x_N,y_N)\} T={(x1,y1),(x2,y2),,(xN,yN)}
其中, x i ∈ χ ⊆ R n x_i\in \chi \sube \bm{R}^n xiχRn为实例的特征向量, y i ∈ Y = { c 1 , c 2 , ⋯   , c K } y_i\in Y= \{c_1,c_2,\cdots, c_K\} yiY={ c1,c2,,cK}为实例的类别, i = 1 , 2 , ⋯   , N i=1,2,\cdots,N i=1,2,,N
输出:实例 x x x所属的类 y y y

  1. 根据给定的距离度量,在训练集 T T T中找出与 x x x最邻近的 k k k个点,涵盖这 k k k个点的 x x x的邻域记作 N k ( x ) N_k(x) Nk(x);
  2. N k ( x ) N_k(x) Nk(x)中根据分类决策规则(如多数表决)决定 x x x的类别 y y y:
    y = arg max ⁡ c j ∑ x i ∈ N k ( x ) I ( y i = c j ) , i = 1 , 2 , ⋯   , N , j = 1 , 2 , ⋯   , K y=\text{arg}\max_{c_j}\sum_{x_i\in N_k(x)}I(y_i=c_j),i=1,2,\cdots,N,j=1,2,\cdots,K y=argcjmaxxiNk(x)I(yi=cj),i=1,2,,N,j=1,2,,K
    其中, I I I为指示函数,即当 y i = c j y_i=c_j yi=cj I I I为1,否则 I I I为0。

k k k近邻法的特殊情况是 k = 1 k=1 k=1的情形,称为最邻近算法。

二、三个基本要素

1.距离度量

k k k近邻模型的特征空间一般是 n n n维实数向量空间 R n \bm{R}^n Rn。使用的是欧氏距离,但也可是其他距离。如更一般的 L p L_p Lp距离。定义空间中两点 x 1 = ( x 1 1 , x 1 2 , ⋯   , x 1 n ) T , x 2 = ( x 2 1 , x 2 2 , ⋯   , x 2 n ) T x_1=(x_1^1,x_1^2,\cdots,x_1^n)^T,x_2=(x_2^1,x_2^2,\cdots,x_2^n)^T x1=(x11,x12,,x1n)T,x2=(x21,x22,,x2n)T L p L_p Lp距离定义为
L p ( x 1 , x 2 ) = ( ∑ l = 1 n ∣ x 1 l − x 2 l ∣ p ) 1 p L_p(x_1,x_2)=\left(\sum_{l=1}^{n}|x_1^l-x_2^l|^p\right)^\frac{1}{p} Lp(x1,x2)=(l=1nx1lx2lp)p1
p = 2 p=2 p=2时,称为欧氏距离,当 p = 1 p=1 p=1时,称为曼哈顿距离。

2. k k k值的选择

   k k k值得选择会对 k k k近邻法的结果产生重大影响。
  如果选择较小的 k k k值,就相当于用较小的邻域中的训练实例进行预测,预测结果会对近邻的实例点非常敏感。如果临近的实例点恰巧是噪声,预测就会出错。换句话说, k k k值得减小就意味着整体模型变得复杂,容易发生过拟合
  如果选择较大的 k k k值,就相当于用较大邻域中的训练实例进行预测,这时与输入实例较远的(不相似的)训练实例也会对预测起作用,使预测发生错误。 k k k值的增大就意味着整体模型变得简单
  在应用中, k k k值一般取一个比较小的数值。通常采用交叉验证法来选取最优的 k k k

3.分类决策规则

这里的分类决策规则就是多数表决,即由输入实例的 k k k个邻近的训练实力中的多数类决定输入实力的类。


三、 k d kd kd

  通过上面的学习,我们就已经明白了 k k k近邻算法的具体步骤,这时你可以采用python等语言的编程实现 k k k近邻算法。
  但是如果训练集中的实例的维数很大以及训练数据容量很大时,我们如果一一计算训练集中的实例点与预测点之间的欧氏距离,并且找出 k k k个近邻时计算非常耗时,这种方法是不可行的。为了提高 k k k近邻搜索的效率,可以考虑使用特殊的结构存储训练数据,以减少计算距离的次数。具体方法很多,这里介绍其中一种 k d kd kd树的方法。

1.构造平衡 k d kd kd

  构造平衡 k d kd kd树。

  1. 开始:构造根节点,根节点包含 T T T k k k维空间的超矩形区域。 选择 x 1 x^1 x1为坐标轴,以 T T T中所有实例的 x 1 x^1 x1坐标的中位数为切分点,将根节点对应的超矩形区域切分为两个子区域。
    由根结点生成深度为1的左、右子节点:左子结点对应坐标 x 1 x^1 x1小于切分点的子区域,右子节点对应坐标 x 1 x^1 x1大于切分点的子区域。
    将落在切分超平面的实例点保存在根结点。
  2. 重复:对深度为 j j j的结点,选择 x l x^l xl为切分轴, l = j ( mod k ) + 1 l=j(\text{mod}k)+1 l=j(modk)+1,以该结点的区域中所有实例的 x l x^l xl坐标的中位数为切分点,将该结点对应的超矩形区域切分为两个子区域。
    由该结点生成深度为 j + 1 j+1 j+1的左、右子结点:左子节点对应坐标 x l x^l xl小于切分点的子区域,右子结点对应坐标 x l x^l xl大于切分点的子区域。
    将落在切分超平面上的实例点保存在该结点。
  3. 指导两个子区域内没有实例存在是停止,从而形成 k d kd kd树的区域划分。

我们直接使用一个例子来展示如何构造 k d kd kd树。
给定一个二维空间的训练数据集
T = { ( 2 , 3 ) T , ( 5 , 4 ) T , ( 9 , 6 ) T , ( 4 , 7 ) T , ( 8 , 1 ) T , ( 7 , 2 ) T } T=\{(2,3)^T,(5,4)^T,(9,6)^T,(4,7)^T,(8,1)^T,(7,2)^T\} T={(2,3)T,(5,4)T,(9,6)T,(4,7)T,(8,1)T,(7,2)T}
构造一个平衡 k d kd kd树。

  1. 第一步,以 x 1 x^1 x1为切分的坐标轴, x 1 x^1 x1维度上的中位数为7,所以我们以7为切分点对数据进行切分。如下图所示:
    在这里插入图片描述
    此时将 ( 7 , 2 ) (7,2) (7,2)点保存在根结点(深度为0),左区域有三个点,右区域有两个点。
  2. 第二步,此时结点的深度为1, l = 1 ( m o d 2 ) + 1 = 2 l=1(mod 2)+1=2 l=1(mod2)+1=2,选择 x 2 x^2 x2为切分的坐标轴。左区域中 x 2 x^2 x2维度上的中位数为4,右区域中 x 2 x^2 x2维度上的中位数为6,据此对左右区域进行切分。如下图所示:
    在这里插入图片描述
    此时的 k d kd kd树如下所示:
    在这里插入图片描述
  3. 第三步,此时的结点的深度为2, l = 2 ( m o d 2 ) + 1 = 1 l=2(mod 2)+1=1 l=2(mod2)+1=1,选择 x 1 x^1 x1为切分的坐标轴。切分后如下图所示:
    在这里插入图片描述
    kd树如下图所示:
    在这里插入图片描述

至此我们发现所有的区域中已经没有实例存在(也就是说没有实例点可以进行划分),所以停止 k d kd kd树的区域划分。

2.用 k d kd kd树进行最近邻搜索

上一节我们已经介绍了如何构造 k d kd kd树,本节我们介绍如何使用 k d kd kd树进行最近邻搜索。
算法如下:
输入:已构造的 k d kd kd树,目标点 x x x
输出: x x x的最近邻。

  1. 从根结点出发,递归地向下访问 k d kd kd树。若目标点 x x x当前维的坐标小于切分点的坐标,则移动到左子节点,否则移动到右子结点,直到子结点为叶结点为止。
  2. 令此叶节点为“当前最近点”(计算点 x x x与此叶结点的距离)。
  3. 递归地向上回退,在每个结点(记为 o o o)进行以下操作:
    • (a)如果该结点 o o o保存的实例点与点 x x x的距离比当前最近点距离点 x x x更近,则以该实例点 o o o作为“当前最近点”。
    • (b)当前最近点一定存在于该结点 o o o一个子结点对应的区域。检查该子结点的父结点 o o o的另一子结点对应的区域是否有更近的点。具体地,检查另一子节点对应的区域是否与以目标点 x x x为球心,以目标点与“当前最近点”间的距离为半径的超球体相交。如果相交,可能在另一个子节点对应的区域内存在距目标点更近的点,移动到另一个子节点。接着,递归地进行最近邻搜索,如果不相交,向上回退。
  4. 当回退到根结点时,搜索结束。最后的“当前最近点”即为 x x x的最近邻点。

我们用一个实例来演示 k d kd kd树进行最近邻搜索的过程。目标点是 x ( 2 , 4.5 ) x(2,4.5) x(2,4.5),要找到 x x x的最近邻。
按照算法流程,第一步结束后,我们移动到 ( 4 , 7 ) (4,7) (4,7)点。移动路径是: ( 7 , 2 ) − ( 5 , 4 ) − ( 4 , 7 ) (7,2)-(5,4)-(4,7) (7,2)(5,4)(4,7)
第二步:令叶节点 ( 4 , 7 ) (4,7) (4,7)为当前最近点 o o o。目标点与最近点 o o o的距离是为3.202。
第三步:递归向上回退,回退到 ( 5 , 4 ) (5,4) (5,4)点。(a)目标点与(5,4)之间的距离为:3.041,所以 ( 5 , 4 ) (5,4) (5,4)点比当前最近点 o o o距离目标点 x x x更近,则更新当前最近点 o o o ( 5 , 4 ) (5,4) (5,4)。(b)以目标点 x x x为圆心,以目标点与“当前最近点 o o o”间的距离为半径的圆与当前最近点 o ( 5 , 4 ) o(5,4) o(5,4)的另一个子节点 ( 2 , 3 ) (2,3) (2,3)对应的区域相交。所以我们移动到 ( 2 , 3 ) (2,3) (2,3)点, ( 2 , 3 ) (2,3) (2,3)点距离目标点比当前的最近点 o ( 5 , 4 ) o(5,4) o(5,4)要近,所以最近点o更新为 ( 2 , 3 ) (2,3) (2,3)。接着继续往上回退为 ( 7 , 2 ) (7,2) (7,2)点, ( 7 , 2 ) (7,2) (7,2)点距离目标点比 ( 2 , 3 ) (2,3) (2,3)点距离目标点要远。
第四步:回退到根结点,搜索结束。此时最近点 o ( 2 , 3 ) o(2,3) o(2,3)为目标点 x ( 2 , 4.5 ) x(2,4.5) x(2,4.5)的最近邻点。

整体的思路大概就是;

  1. 先进行二分查找到叶结点
  2. 回溯搜索路径
  3. 检查另一子结点区域是否有更近的
  4. 搜索另一个子空间
  5. 最后回溯到根结点

四、参考链接

代码链接:https://github.com/zgaxddnhh/lihang-code
参考书籍:机器学习方法.李航

猜你喜欢

转载自blog.csdn.net/qq_41596730/article/details/127770363