第三章:K近邻算法
算法概述
K近邻算法是一种多分类与回归的算法,这里只讨论分类模型中的KNN算法;算法的基本思想是,对于一个目标实例x,根据与其相距最近(这里涉及到距离度量)的 k 个点的类别,由多数表决原则,来决定目标实例所属的类别;特别的,当 k =1 时,为最近邻算法;
KNN算法有三要素:k值的选择(影响到模型的复杂度,过/欠拟合问题)、距离度量、分类决策;
KNN模型
模型
当训练集、k值、距离度量、分类决策确定之后,对于任何一个新的输入实例,他所属的类被唯一确定;相对于将特征空间划分为一些子空间,确定每个子空间里的点所属的类;
距离度量
有多种距离度量的方法,一般采取闵氏距离:
L
p
(
x
i
,
x
j
)
=
(
∑
l
=
1
n
∣
x
i
(
l
)
−
x
j
(
l
)
∣
p
)
1
p
L_{p}(x_i,x_j) = (\displaystyle\sum_{l=1}^{n}|{x_i^{(l)}} -{x_j^{(l)}}|^p)^{\frac{1}{p}}
Lp(xi,xj)=(l=1∑n∣xi(l)−xj(l)∣p)p1;
这里,有
p
≥
1
p\geq1
p≥1,
当 p = 2,为欧式距离;
L
p
(
x
i
,
x
j
)
=
(
∑
l
=
1
n
∣
x
i
(
l
)
−
x
j
(
l
)
∣
2
)
1
2
L_{p}(x_i,x_j) = (\displaystyle\sum_{l=1}^{n}|{x_i^{(l)}} -{x_j^{(l)}}|^2)^{\frac{1}{2}}
Lp(xi,xj)=(l=1∑n∣xi(l)−xj(l)∣2)21;
p = 1时,为曼哈顿距离(街区距离);
L
p
(
x
i
,
x
j
)
=
∑
l
=
1
n
∣
x
i
(
l
)
−
x
j
(
l
)
∣
L_{p}(x_i,x_j) = \displaystyle\sum_{l=1}^{n}|{x_i^{(l)}} -{x_j^{(l)}}|
Lp(xi,xj)=l=1∑n∣xi(l)−xj(l)∣;
p = 无穷大,值为各个坐标距离的最大值:
L
p
(
x
i
,
x
j
)
=
m
a
x
∣
x
i
(
l
)
−
x
j
(
l
)
∣
L_{p}(x_i,x_j) = max|{x_i^{(l)}} -{x_j^{(l)}}|
Lp(xi,xj)=max∣xi(l)−xj(l)∣;
l
l
l= 1,2,3…n;
k值的选择
k值的大小影响到模型的复杂度:随着k越大,模型就越简单,表现为欠拟合,学习的近似误差会增大,估计误差会减小;反之可推k值减小的情况;
近似误差:理解为对训练集的误差;
估计误差:理解为对测试集的误差;
在实际应用中,一般取较小的 k 值,然后使用交叉验证来选择合适的 k 值;
分类决策
采取多数表决的方式,即 k 个点中,大多数点所属的类别即为这一区域内的类别;这样与最小化经验风险函数是等价的;
KD树
KD树是一种对k维空间中的实例点进行存储以便对其进行快速检测的树形数据结构,是一颗二叉树;表示对 k 维空间的划分;树的内部结点保存落在切分平面上的点以及保存一些分类信息(选择的维度以及切分值等)),叶子结点用于保存剩下的实例,每一个叶子结点都对应一部分 k维空间; 这 样 每 个 结 点 只 包 含 一 个 实 例 \color{red}{这样每个结点只包含一个实例} 这样每个结点只包含一个实例;
建立kd树
- 建立根节点,以第一维度为分界标识,取第一维度的中位数为切分点,将 k 维空间分为两部分,分别对应该结点的左右子树,左子树中储存该维度小于切分点的实例,右子树储存该维度大于等于切分点的实例;
- 选择新的维度,具体来说,树的深度(根结点深度为0)j 对应的维度为 l = j mod(k)+1;然后重复1;
- 直至两个子树中不再存在实例,结束;
kd树的KNN搜索
给定一个构建于一个样本集的 kd 树,下面的算法可以寻找距离某个点 p 最近的 k 个样本。
零、设 L 为一个有 k 个空位的列表,用于保存已搜寻到的最近点。
一、根据 p 的坐标值和每个节点的切分向下搜索(也就是说,如果树的节点是按照
x
r
=
a
x_r=a
xr=a 进行切分,并且 p 的 r 坐标小于 a,则向左枝 进行搜索;反之则走右枝)。
二、当达到一个底部节点时,将其标记为访问过。如果 L 里不足 k 个点,则将当前节点的特征坐标加入 L;如果 L 已满并且当前节点 的特征与 p 的距离小于 L 里最长的距离,则用当前特征替换掉 L中离 p 最远的点。
三、如果当前节点不是整棵树最顶端节点,执行 (a);反之,输出 L,算法完成。
a. 向上爬一个节点。如果当前(向上爬之后的)节点未曾被访问过,将其标记为被访问过,然后执行 (1) 和 (2);如果当前节点访问过,再次执行 (a)。
- 如果此时 L 里不足 k 个点,则将节点特征加入 L;如果 L 中已满 k 个点,且当前节点与 p 的距离小于 L 里最长的距离,则用节点特征替换掉 L中离最远的点。
- 计算 p 和当前节点切分线的距离。如果该距离大于等于 L 中距离 p 最远的距离并且 L 中已有 k 个点,则在切分线另一边不会有更近的点,执行(三);如果该距离小于 L 中最远的距离或者 L 中不足 k 个点,则切分线另一边可能有更近的点,因此在当前节点的另一个枝从 (一) 开始执行。