统计学习方法(3)

第三章 KNN

KNN的实现:k-d树

k-d tree的 wikipedia链接

构造 k-d 树

将整个数据集的\(k\)维空间定为根节点,树的深度为 \(1\),然后进行迭代划分。
每次迭代,树的深度加 \(1\),按照树的深度,轮流选择第 \(i\) 维为当前划分的维度。
按照当前子空间中所有数据的第\(i\)维的中位数对当前子空间进行切分。
中位数节点为下一次迭代的根节点。

搜索 k-d 树

  1. 在 k-d 树中找出包含目标点 \(x_i\) 的叶结点:从根结点出发,递归地向下搜索 k-d 树。若目标点 \(x_i\) 当前维的坐标小于切分点的坐标,则移动到左子结点,否则移动到右子结点,直到子结点为叶结点为止。
  2. 以此叶结点为“当前最近点”。
  3. 递归的向上回溯,在每个结点进行以下操作:
    1. 如果该结点保存的实例点比当前最近点距离目标点更近,则更新“当前最近点”,也就是说以该实例点为“当前最近点”。
    2. 当前最近点一定存在于该结点一个子结点对应的区域,检查子结点的父结点的另一子结点对应的区域是否有更近的点。具体做法是,检查另一子结点对应的区域是否以目标点位球心,以目标点与“当前最近点”间的距离为半径的圆或超球体相交:
      如果相交,可能在另一个子结点对应的区域内存在距目标点更近的点,移动到另一个子结点,接着,继续递归地进行最近邻搜索;
      如果不相交,向上回溯。
  4. 当回退到根结点时,搜索结束,最后的“当前最近点”即为 \(x_i\) 的最近邻点。

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

上述算法为寻找最近的邻居节点,若要寻找最近的 \(K\) 个邻居节点,则要维护一个大小为 \(K\) 的最大堆。当且仅当已找到 \(K\) 个当前最近节点,切新分支内的节点均不能更新最小堆时才放弃搜索这个分支。

效率更高一些的搜索算法可见 wikipedia

posted @ 2015-01-25 11:06  京酱肉丝不搁葱  阅读(138)  评论(0)    收藏  举报