KNN-KD树

提示:仅供自己学习、复习需要,有任何问题可在评论区提出。

一、KD树与KNN的关系

K近邻(KNN)算法,是机器学习中常用的分类算法,要判断样本数据是谁,就是简单的判断他的邻居是谁,我们就认为他属于跟他邻居是同一类。K代表的是样本最近邻居的个数,K等于3表示通过离的最近的3个邻居来判断类别,通过距离判断他们的关系,距离可以使用欧氏距离或者曼哈顿距离来计算。KNN算法的流程就是计算样本点与所有数据点的距离,然后由近到远进行排序,选出离的最近的k个邻居,因此数据越多,计算量越大,效率越低。为了提高kNN搜索的效率,我们这里提出的KD树,以减小计算距离的次数,提高效率。

二、KD树

1.相关概念

  1. kd树(K-dimension tree)是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构。
  2. kd树是是一种二叉树,表示对k维空间的一个划分,构造kd树相当于不断地用垂直于坐标轴的超平面将K维空间切分,构成一系列的K维超矩形区域。kd树的每个结点对应于一个k维超矩形区域。
  3. 利用kd树可以省去对大部分数据点的搜索,从而减少搜索的计算量。

2.原理

构建KD树
如下图,给定一个二维空间数据集: T = ( 2 , 3 ) , ( 5 , 4 ) , ( 9 , 6 ) , ( 4 , 7 ) , ( 8 , 1 ) , ( 7 , 2 ) T={(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)} T=(2,3),(5,4),(9,6),(4,7),(8,1),(7,2),构造一个平衡KD树。
首先进行切分数据空间
我们将横轴作为 x ( 1 ) x^{(1)} x(1),竖轴作为 x ( 2 ) x^{(2)} x(2),首先从 x ( 1 ) x^{(1)} x(1)划分,所有数据的横坐标为 ( 2 , 4 , 5 , 7 , 8 , 9 ) {(2,4,5,7,8,9)} (2,4,5,7,8,9),取其中位数作为划分标准,因为是偶数个,所以中位数应该是6,所以我们可以选择5或7,这里以较大值为例选择7。然后从 x ( 1 ) = 7 x^{(1)}=7 x(1)=7的左子空间以 x ( 2 ) x^{(2)} x(2)进行划分,所有数据的纵坐标为 ( 3 , 4 , 7 ) {(3,4,7)} (3,4,7),中位数是4,所以选择 x ( 2 ) = 4 x^{(2)}=4 x(2)=4为划分为上下两个子空间,,以此类推划分 x ( 1 ) = 7 x^{(1)}=7 x(1)=7的右子空间。最后形成如下图。
请添加图片描述

KD树搜索
步骤:
1.二叉树搜索比较待查询节点和分裂节点的分裂维的值,(小于等于就进入左子树分支,大于就进入右子树分支直到叶子结点)。
2.顺着“搜索路径”找到最近邻的近似点。
3.回溯搜索路径,并判断搜索路径上的结点的其他子结点空间中是否可能有距离查询点更近的数据点,如果有可能,则需要跳到其他子结点空间中去搜索。
4.重复这个过程直到搜索路径为空。

查找目标 ( 3 , 4.5 ) (3,4.5) (3,4.5)的最邻近点:
进行二叉查找,先从根节点(7,2)出发,以 x ( 1 ) x^{(1)} x(1)为标准,对比横坐标的值(3<7),查找(7,2)的左子空间,找到(5,4)节点,然后以 x ( 2 ) x^{(2)} x(2)为标准比较纵坐标的值(4.5>4),查找(5,4)的右子空间找到点(4,7),形成搜索路径:(7.2)→(5.4)→(4.7),取(4,7)为当前最近邻点。以目标查找点为圆心,目标点到当前最近点的距离2.69为半径确定一个红色的圆。然后回溯到(5.4),计算其与查找点之间的距离为2.06,因为2.06<2.69,则把(5.4)作为当前最近邻点。用同样的方法再次确定一个绿色的圆,可见该圆和 x ( 2 ) = 4 x^{(2)}=4 x(2)=4超平面相交,所以需要进入(5,4)结点的另一个子空间进行查找。(2,3)结点与目标点距离为1.8,比当前最近点要更近,所以最近邻点更新为(2,3),最近距离更新为1.8,同样可以确定一个蓝色的圆。接着根据规则回退到根结点(7,2),蓝色圆与 x ( 1 ) = 7 x^{(1)}=7 x(1)=7的超平面不相交,因此不用进入(7,2)的右子空间进行查找。至此,搜索路径回溯完,返回最近邻点(2.3),最近距离1.8。
在这里插入图片描述

参考https://blog.csdn.net/qq_41745284/article/details/114463902?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171101345016777224461906%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=171101345016777224461906&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-114463902-null-null.142v99pc_search_result_base9&utm_term=kd%E6%A0%91%E6%90%9C%E7%B4%A2&spm=1018.2226.3001.4187
https://www.bilibili.com/video/BV1d5411w7f5/?spm_id_from=333.337.search-card.all.click&vd_source=ce384c1ab775f62228b1966cd93401b7

  • 35
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个简单的KD树KNN算法Python代码实现: ``` import numpy as np class KDTree: def __init__(self, data): self.k = data.shape[1] self.data = data self.left = None self.right = None self.split_dim = None self.split_value = None self.build() def build(self): if self.data.shape[0] == 0: return self.split_dim = np.argmax(np.var(self.data, axis=0)) self.split_value = np.median(self.data[:, self.split_dim]) left_data = self.data[self.data[:, self.split_dim] < self.split_value] right_data = self.data[self.data[:, self.split_dim] >= self.split_value] self.left = KDTree(left_data) self.right = KDTree(right_data) def search_knn(self, point, k): heap = [] self._search_knn(point, k, heap) return [h[1] for h in heap] def _search_knn(self, point, k, heap): if self.data is None: return dist = np.linalg.norm(point - self.data) if len(heap) < k: heap.append((dist, self.data)) heap.sort(key=lambda x: x[0]) elif dist < heap[-1][0]: heap[-1] = (dist, self.data) heap.sort(key=lambda x: x[0]) if self.left is None and self.right is None: return if point[self.split_dim] < self.split_value: self.left._search_knn(point, k, heap) if point[self.split_dim] + heap[-1][0] >= self.split_value: self.right._search_knn(point, k, heap) else: self.right._search_knn(point, k, heap) if point[self.split_dim] - heap[-1][0] < self.split_value: self.left._search_knn(point, k, heap) # 使用示例 data = np.random.rand(50, 2) tree = KDTree(data) point = np.array([0.5, 0.5]) k = 5 knn = tree.search_knn(point, k) print(knn) ``` 以上代码实现了一个简单的KD树KNN算法,可以用于查找数据集中与给定点最近的k个点。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值