统计学习方法(3)
第三章 KNN
KNN的实现:k-d树
k-d tree的 wikipedia链接
构造 k-d 树
将整个数据集的\(k\)维空间定为根节点,树的深度为 \(1\),然后进行迭代划分。
每次迭代,树的深度加 \(1\),按照树的深度,轮流选择第 \(i\) 维为当前划分的维度。
按照当前子空间中所有数据的第\(i\)维的中位数对当前子空间进行切分。
中位数节点为下一次迭代的根节点。
搜索 k-d 树
- 在 k-d 树中找出包含目标点 \(x_i\) 的叶结点:从根结点出发,递归地向下搜索 k-d 树。若目标点 \(x_i\) 当前维的坐标小于切分点的坐标,则移动到左子结点,否则移动到右子结点,直到子结点为叶结点为止。
- 以此叶结点为“当前最近点”。
- 递归的向上回溯,在每个结点进行以下操作:
- 如果该结点保存的实例点比当前最近点距离目标点更近,则更新“当前最近点”,也就是说以该实例点为“当前最近点”。
- 当前最近点一定存在于该结点一个子结点对应的区域,检查子结点的父结点的另一子结点对应的区域是否有更近的点。具体做法是,检查另一子结点对应的区域是否以目标点位球心,以目标点与“当前最近点”间的距离为半径的圆或超球体相交:
如果相交,可能在另一个子结点对应的区域内存在距目标点更近的点,移动到另一个子结点,接着,继续递归地进行最近邻搜索;
如果不相交,向上回溯。
- 当回退到根结点时,搜索结束,最后的“当前最近点”即为 \(x_i\) 的最近邻点。
如果实例点是随机分布的,那么 k-d 树搜索的平均计算复杂度是 $O(N\log N) $,这里的 \(N\) 是训练实例数。所以说,k-d 树更适用于训练实例数远大于空间维数时的 KNN 搜索,当空间维数接近训练实例数时,它的效率会迅速下降,几乎接近线性扫描的速度。
上述算法为寻找最近的邻居节点,若要寻找最近的 \(K\) 个邻居节点,则要维护一个大小为 \(K\) 的最大堆。当且仅当已找到 \(K\) 个当前最近节点,切新分支内的节点均不能更新最小堆时才放弃搜索这个分支。
效率更高一些的搜索算法可见 wikipedia

浙公网安备 33010602011771号