0.4kd-tree

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()

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值