KD-Tree
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import scipy as sc
import seaborn as sns
import queue
from sklearn.neighbors import KDTree
from sklearn import datasets
- 随机生成一些数据点
x,y=datasets.make_blobs(n_features=2)
for i in list(set(y)):
plt.plot(x[y==i][:,0],x[y==i][:,1],'*',label=i)
plt.legend()
plt.show()
0. KNN
- 举手表决,选择得到票数最多的类别
1.k-Dimension tree
- K近邻的实现:kd树
1.2首先实现查找树
-
它或者是一棵空树;或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值; (2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值; (3)左、右子树也分别为二叉排序树
class Node():
'''
单棵树的实现
其中:左树是一颗树,右树也是一颗树, 每棵树包含他的子节点和数据集和value
'''
def __init__(self,data,lnode=None,rnode=None,value=None,iIndex=None):
self.rnode=rnode #保存右树
self.lnode=lnode #保存左树
self.value=value #保存切割点
self.data=data #保存数据集
self.iIndex=iIndex #记录切割的维度
def set_node(self,lnode=None,rnode=None,value=None,iIndex=None):
self.rnode=rnode
self.lnode=lnode
self.value=value
self.iIndex=iIndex
1.3 KD树
- 当树不停切分的时候,节点会不停增多,怎么处理呢?
- 把产生的所有的树都加入队列中,然后选择一个出来
def kdTree(data,iIndex):
'''
对数据集切割
对数据的第iIndex个维度分割
包含左侧数据集的树节点,右侧数据集节点,切分点
'''
value=np.median(data[:,iIndex])
#value=np.mean(data[:,iIndex])
right=data[data[:,iIndex]>=value]
left=data[data[:,iIndex]<value]
return Node(left),Node(right),value
1.4 构造简单kd树
- 切割的维度轮着来
- 每次切割按照中位数 或平均数
i=0 # 维度
kd=Node(x) #生成根节点
myqueue=queue.Queue() #空队列
myqueue.put(kd) #加入根节点
while not myqueue.empty():
'''
获取节点,分割节点,将分割好的左右树加入当前节点,
若分割后的节点符合在分割的要求,则将节点加入队列
'''
iIndex=i%(x.shape[1]) #对维度循环
currentNode=myqueue.get() #获取节点
left,right,value=kdTree(currentNode.data,iIndex)# 分割该节点
currentNode.set_node(left,right,value,iIndex)#设置根节点的左右节点
if len(left.data)>1:#至少有两个数据
myqueue.put(left)
if len(right.data)>1:#至少有两个数据
myqueue.put(right)
i+=1
1.5 搜索kd树
- 查询的时候按照每个维度是值
- 如果当前节点的数据数少于2,则不会继续分割,所以他的子节点肯定是None
search=[-9,0]# 查找(0,0)点的最近邻
currentNode=kd
while currentNode.rnode!=None:
if currentNode.value>search[currentNode.iIndex]:
#选择左子树
currentNode=currentNode.lnode
elif currentNode.value<search[currentNode.iIndex]:
#选择右
currentNode=currentNode.rnode
print(currentNode.data)
[[-8.49693735 0.07710253]]
#画一下数据集
for i in list(set(y)):
plt.plot(x[y==i][:,0],x[y==i][:,1],'*',label=i)
plt.plot(currentNode.data[:,0],currentNode.data[:,1],'bo',label='find_result',alpha=0.2)
plt.plot(search[0],search[1],'bo',label='target')
plt.legend()
plt.show()