算法流程
输入:训练数据集 T = { ( x i , y i ) } i = 1 N T=\{(x_i, y_i)\}^N_{i=1} T={(xi,yi)}i=1N, 其中 x i x_i xi为实例的特征向量, y i ∈ { c 1 , c 2 , . . . , c k } , i = 1 , 2 , . . . , N y_i\in \{c_1, c_2, ..., c_k\}, i=1,2,...,N yi∈{c1,c2,...,ck},i=1,2,...,N,实例特征向量 x x x。
输出:实例 x x x对应的类别 y y y。如果k=1, 则对应的算法为最近邻算法。
- 根据给定的距离度量,在T中寻找与 x x x最近的k个点,涵盖这k个点的x的邻域记作 N k ( x ) N_k(x) Nk(x)。
- 在
N
k
(
x
)
N_k(x)
Nk(x)中根据分类决策规则决定
x
x
x的类别。
y = a r g m a x c j ∑ x i ∈ N k ( x ) I ( y i = c j ) , i = 1 , 2 , . . . , N ; j = 1 , 2 , . . . , K y= argmax_{c_j}\sum _{x_i\in N_k(x)}I(y_i=c_j), i=1,2,...,N; j=1,2,...,K y=argmaxcjxi∈Nk(x)∑I(yi=cj),i=1,2,...,N;j=1,2,...,K
模型概述
当训练集、距离度量、k值及分类决策规律确定下来后,对于任意的输入实例,它所属的类都是唯一确定的,这相当于把特征空间划分为一些子空间。
值得注意的是,如果k选的太小,则近似误差会减小,估计误差会变大,模型会变复杂,容易发生过拟合,容易受到噪声的干扰,如果k选的太大,则估计误差变小,但近似误差会增大,这样模型会变复杂。
分类决策规则一般都是多数表决,多数表决的损失函数为0-1损失函数,分类函数为
f
:
R
n
→
{
c
1
,
c
2
,
.
.
.
,
c
n
}
f:R^n\rightarrow \left \{ c_1, c_2,...,c_n \right \}
f:Rn→{c1,c2,...,cn}
如果对于输入的实例
x
x
x,其最临近的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
j
)
=
1
−
1
k
∑
x
i
∈
N
k
(
x
)
I
(
y
i
=
c
j
)
\frac{1}{k}\sum _{x_i \in N_k(x)}I(y_i\neq c_j)=1-\frac{1}{k}\sum _{x_i \in N_k(x)}I(y_i= c_j)
k1xi∈Nk(x)∑I(yi=cj)=1−k1xi∈Nk(x)∑I(yi=cj)
注意,这里的误分类率指的是一个样本的误分类率,而不是所有输入样本的误分类率。
模型细节
构造kd树
kd树是二叉树,表示对k维空间的一个划分,构造平衡kd树的算法如下,但平衡kd树不见得是最好的。
输入:k维空间数据集 T = { x 1 , x 2 , . . . , x N } T=\{x_1,x_2,...,x_N\} T={x1,x2,...,xN}, 其中 x i = ( x i ( 1 ) , x i ( 2 ) , . . . , x i ( k ) ) , i = 1 , 2 , . . . , N x_i=(x_i^{(1)},x_i^{(2)},...,x_i^{(k)}), i=1,2,...,N xi=(xi(1),xi(2),...,xi(k)),i=1,2,...,N
输出: kd树,构造过程如下所示:
- 构造根节点,根节点对应包含T的k维空间,选择 x ( 1 ) x^{(1)} x(1)为坐标轴,以T中所有实例的 x ( 1 ) x^{(1)} x(1)坐标的中位数为切分点,切分由通过切分点并与坐标轴 x ( 1 ) x^{(1)} x(1)垂直的超平面实现,切分为两个子节点,左子节点中存放的是 x ( 1 ) x^{(1)} x(1)较小的子区域,右子节点存放的是 x ( 1 ) x^{(1)} x(1)较大的子区域,将落在切分超平面的实例点保存在根节点。
- 对于深度为 j j j的节点,选择 x ( l ) x^{(l)} x(l)为切分的坐标轴, l = j % k + 1 l=j\ \% \ k+1 l=j % k+1, 再次切分这这两个子区域,而后生成深度为 j + 1 j+1 j+1的左右子节点,同样,将落在切分超平面上实例点保存在该节点。
- 重复第2步,直到两个子区域没有实例存在停止。
通俗易懂的说法是开始从第一维开始,选择大于中位数的放到右节点,小于中位数的放到左节点,而后选择第二维,分别对左右节点实施同样的操作,构造kd树。
搜索kd树
这里只介绍对于kd树如何进行最近邻搜索,k近邻也是一样的,实质上就是在找训练集中与 x x x最临近的那个点,
输入: 已经构造的kd树,目标点 x x x,
输出: x x x的最近邻,搜索构成如下所示:
- 在kd树中找到包含 x x x的叶节点,经过与树中节点的比较,目标点会落在某一个叶节点上。
- 定义此节点为最近点。
- 递归的向上回退,在每个节点执行:
1. 如果该节点保存的实例点比当前最近点距离目标点更近,则更新最近点为该实例点。
2. 检查该节点的父节点的另一个子节点是否存在更近的点,具体地,检查另一子节点对应的子树中是否与以目标点为球心,以目标点与当前最近点的距离为半径的超球体相交,如果相交,则移动到另一节点,接着递归的完成最近邻搜索,如果不相交,则回退。 - 当回退到根节点时,搜索结束,最后的当前最近点为 x x x的最近点。