KD-Tree应用于中低量的维度数据,是检索二叉树,可以很快速的完成检索,但是对于大量的维度数据,速度慢就不能用,此时用的是LSH。
算法的步骤:
这里假定多维度向量组成的shape是[rows,cols],每行是一个向量,由于是检索,所以有多行向量,rows行就组成这个矩阵,接着构建二叉树
矩阵有行维度,也有列维度,找划分节点就需要找能将行尽可能划分开的节点,这里按列计算并寻找方差最大的列 H,对列H找出其中的中位数M,这样中位数M所在的行就是根节点,这行也是分割面
根据根节点划分,列H中的数,大于M的所在行分到根节点的右侧,小于M的所在行分到左侧
对于左右两侧,分别循环上面划分节点的步骤,直到划分以后只有一行向量
KD-Tree举例:
有5个向量用来检索
x1=[9,10],x2=[12,16],x3=[16,19],x4=[19,6],x5=[19,10]
shape=[2,2],方差为:[15.6 , 21.76],var2>var1,第二列的中位数是10
令x1是划分节点,x4,x5在左侧,x2、x3在右侧,
x1
x4、x5 x3、x2
由于第二列用来划分过一次,接着用第一列划分,x4和x5的中位数是19,x2和x3的中位数是14
x1
x5 x4 x2 x3
检索过程可以根据根节点的记录信息即划分的维度是第几维H,用第H维的数据对比,然后不断寻找直到找到结点。
Python实现:
import numpy as np
np.random.seed(99999)
v=np.random.randint(19,size=(10,2));print(v)
def KDTree(matrix):
if len(matrix)==2:
return {tuple(matrix[0]),tuple(matrix[1])}
if len(matrix)==1:
return {tuple(matrix[0])}
if len(matrix)==0:
return {}
matrix=np.array(matrix)
vars=list(matrix.var(0)) #按列计算矩阵的方差
ind=vars.index(max(vars)) #找出方差最大所在列的列号
m=list(matrix[:,ind])
m.sort()
middle=m[len(m)//2] #找到该列的中位数
lm=[]
rm=[]
for i in range(matrix.shape[0]): #遍历所有行然后分配到左右子树
if matrix[i,ind]==middle:
continue
if matrix[i,ind]<middle:
lm.append(list(matrix[i,:]))
else:
rm.append(list(matrix[i,:]))
kdtree={(ind,middle):{}} #ind记录检索时的列号,middle是比对的值
kdtree[(ind,middle)]=[KDTree(lm),KDTree(rm)] #递归生成左右子树
return kdtree
print(KDTree(v))
生成的结果:
[[11 16]
[12 14]
[15 12]
[17 11]
[17 3]
[15 14]
[ 6 16]
[16 0]
[12 18]
[16 16]]
{(1, 14): [{(1, 11): [{(16, 0), (17, 3)}, {(15, 12)}]}, {(0, 12): [{(11, 16), (6, 16)}, {(16, 16)}]}]}