在KNN算法中,当样本数据量非常大时,快速地搜索k个近邻点就成为一个难题。kd树搜索算法就是为了解决这个问题。本篇博客主要介绍多维数据kd树搜索算法的Python实现。
本篇博客不对二叉树进行详细介绍,只提及一些比较重要的概念。
ADT BinTree:
BinTree(self, data, left, right) #构造函数,创建一个新的二叉树
is_empty(self) #判断self是否为一个空二叉树
num_nodes(self) #求二叉树的结点个数
data(self) #获取根结点存储的数据
left(self) #获得二叉树的左子树
right(self) #获得二叉树的右子树
set_left(self, btree) #用btree取代原来的左子树
set_right(self,btree) #用btree取代原来的右子树
traversal(self) #遍历二叉树中各节点数据的迭代器
forall(self, op) #对二叉树中的每个结点的数据执行操作
kd树是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构。kd树是二叉树,表示对k维空间的一个划分。构造kd树相当于不断用垂直于坐标轴的超平面将k维空间切分,构成一系列的k维超矩形区域。kd树的每个结点对应于一个k维超矩形区域。
输入:k维空间数据集 T = { x 1 , x 2 , . . . , x N } T=\{ x_{1},x_{2},...,x_{N}\} T={x1,x2,...,xN},N表示样本个数。
其中 x i = ( x i 1 , x i 2 , . . . , x i k ) T , i = 1 , 2 , . . . , N x_{i} = (x_{i}^{1},x_{i}^{2},...,x_{i}^{k})^{T},i=1,2,...,N xi=(xi1,xi2,...,xik)T,i=1,2,...,N
输出:kd树
输入:已构造的kd树;目标点x;
输出:x的最邻近
如果实例点是随机分布的,kd树更适用于训练样本数远大于空间维数时的k近邻搜索。当空间维数接近训练实例数时。它的效率会迅速下降,几乎接近线性扫描。
建立kd树
初始维度设为dim = 0
def creat(points,dim):
if points is not None:
1.找到所有样本点(points)在第dim维度下的坐标的中位点,记为point[media]
2.确定过该中位点且垂直于第dim维坐标轴的一个超平面。(只是一个概念无需体现在代码中)
3.该超平面将空间分为两个子空间。该中位点则作为当前kdtree的根结点 root.data=point[media]
4.在第dim维度下,小于该中位点的所有样本点被划分到左子树,记为lefts点集
5.大于该中位点的所有样本点被划分到右子树,记为rights点集.
递归执行:root.left = creat(lefts,(dim+1)% m)
递归执行:root.right = creat(rights,(dim+1)% m)
return root
else:
return None
搜索最近邻点
def research_nn(point):
1.遍历:将point点的坐标对应维度与kdtree的结点进行比较,小于结点对应维度的值往左子树走,反之往右子树走,等于的话就停止,或者知道kdtree的叶子结点再停止。将经过的所有节点坐标依次压入栈stack。以最后停下来的点(stack.pop)作为最近零点,并计算距离dist_min
2.回溯:
def back(point, dist):
leaf = stack.pop
计算leaf与point的距离,记为dist
if dist <= dist_min:
dist_min=dist
return
else:
计算point到leaf的父结点所在的超平面的距离,记为dist
if dist_min
使用开源的KDTree库函数,详情见https://mp.csdn.net/mdeditor/87977160#
1.李航,统计学习方法,清华大学出版社。
2.裘宗燕,数据结构与算法python语言描述,机械工业出版社。