统计学习方法——K近邻法【k-NN】(二)

kk近邻的实现——kdkd

kk近邻的主要工作量是:找到到样本最近的kk个点。最简单的无疑是线性扫描,但数据量太大时非常耗时不可行,因此提出了kdkd树。

kdkd

构造kdkd

  • 特点
    • 一种对kk维空间中的实例点进行存储以便进行快速检索的树形结构
    • 是二叉树
    • 构造kdkd树相当于不断用垂直于坐标轴的超平面将kk维空间划分
    • 树的每个结点对应于一个kk维超矩阵区域
  • 构造方法
    输入维kk维空间数据集T={x1,x2, ,xN}T = \left\{ {{x_1},{x_2}, \cdots ,{x_N}} \right\},其中xi=(xi(1),xi(2), ,xi(k))T{x_i} = {\left( {x_i^{\left( 1 \right)},x_i^{\left( 2 \right)}, \cdots ,x_i^{\left( k \right)}} \right)^T}
    • 构造根节点,根节点对应于包含kk维空间所有实例点的超矩阵区域
    • 选择x(1){x^{\left( 1 \right)}}为坐标轴,以TT中所有实例的x(1){x^{\left( 1 \right)}}坐标的中位数为切分点,通过切分点并垂直于x(1){x^{\left( 1 \right)}}坐标轴的超平面将根节点的矩形区域分为两个子区域。
    • 由根节点生成深度为11的左、右子节点,左子节点对应坐标x(1){x^{\left( 1 \right)}}小于切分点的子区域,右子节点则是大于的。
    • 重复:对深度为jj的结点,选择x(l){x^{\left( l \right)}}为切分的坐标轴,l=j( mod k)+1l = j\left( {\bmod k} \right) + 1
    • 直到两个区域都没有实例为止,形成kdkd树的区域划分。

注:通过中位数分割得到的kdkd树是平衡的,但平衡kdkd树的搜索效率未必是最优的。

kdkd树的搜索方法

这里我们以最近邻为例,介绍搜索算法。

  • 输入:构造好的kdkd树,目标点xx
  • 输出:xx的最近邻
  • 搜索
    • kdkd树中找到包含目标点xx的叶节点。
      从根节点出发,若目标点xx当前维德坐标小于切分点则向左移动,否则向右,直到叶子节点为止。
    • 从此结点为“当前最近点”,向上回退,并执行
      • 如果该节点该结点比当前最近点离目标更近,则以此结点作为“当前最近点”
      • 当前最近点必然存在于该节点的一个子节点对应的区域,检查另一子节点的区域是否与(以目标点为球心,目标点到当前最近点距离为半径的超球体)相交,若相交则移动到另一个子节点,继续递归,不相交则向上回退。
    • 回退到根节点结束。
      kdkd树搜索的平均计算法复杂度为O(logN)O\left( {\log N} \right)NN为训练实例数。
      kdkd树更适合训练实例远大于空间维数时的kk近邻搜索。

简单示例

如图所示的kdkd树,求S的最近邻(这里考虑欧式距离)。
统计学习方法——K近邻法【k-NN】(二)
其实将其转化为树的形式为:
统计学习方法——K近邻法【k-NN】(二)
整个搜索过程对比两个图,应该是:

  1. 从根节点开始,向下找到包含SS的结点DD,此时最近点也为DD
  2. DD向上搜索,BB显然比DDSS
  3. 搜索BB的另一个子节点,FF并不与此时C的圆相交,显然也不是
  4. 向上回退到AAAA不能成为最近点
  5. 搜索AA的另外一边,发现与圆相交,说明在另一边存在最近点
  6. 在另一边搜索会找到点EE,也就是真正的最近点