KD tree 实现

(感谢前辈)转自:https://zhuanlan.zhihu.com/p/73002544

评价: 代码需要优化,处理数据消耗时间较长


之前提到了,用 DBSCAN 聚类的时候,由于 DBSCAN 需要计算每两个点两两之间的距离,超过5万个点就是25万的距离矩阵,就直接报内存错误了,查看任务管理器发现内存占用达到了5-9G;尽管后续极力压缩,还是需要5-6秒的时间,这显然是不可接受的,所以就想用 kdtree 代替原有的距离矩阵来搜索临近点;


参考了 Python 实现 KD-Tree 最近邻算法 一部分代码;但是基本网上能找到的代码都没有搜索一定半径内点的部分,所以自己加上了,然后把它修改为numpy的版本;

1 构造树的时候没有使用方差最大的方向来分割,而是循环使用XYZ方向分割空间;

2 递归分割直到每个点都是唯一的叶子节点,没有剪枝的过程(有的话是不是效率更快?);

3 半径搜索从根节点开始,然后对点到分割平面的距离与搜索半径R进行比较,决定是否需要进入节点的相邻子空间进行查找,一直递归这个过程;

代码如下:

from collections import namedtuple
import numpy as npclass kd_node_index(namedtuple('kd_node', 'node ori_index left_child right_child  split_axis')):passclass my_KDTree_index():# k-dimensional treedef __init__(self, points):if points.shape[1] != 3:print('points must be array, and should be N*3 shape.')self.dimension = 3  # 数据点的维度,限定在点云的三维空间# tree 就是最后的结果,KDtree 实际上就是一个多维二叉树indexs1 = np.arange(points.shape[0])self.tree = self._make_kdtree_index(points,indexs=indexs1)def _make_kdtree_index(self, points, indexs=None, depth=0):# 构建 node 是索引的 kd 树# 递归需要这个语句来终止if points.size == 0:return None# 每次分割的维度没有保存的吗?# 另外,不是根据方差来选取划分点吗? 这样有没有区别?这样就是轮流的选择xyz了axis = depth % self.dimension# 先排序,指定用第几维的数据进行排序;# 如果不排序,随机呢?将不能保证左右子树的大小顺序index_array = np.argsort(points[:, axis])indexs_sorted = indexs[index_array]# 然后用长度除以2的结果作为中值median = points.shape[0] // 2# 递归的形成 kd-treereturn kd_node_index(node=points[index_array[median]],  # 其实,返回了ori_index后,node就不太需要了;ori_index = indexs_sorted[median],left_child =self._make_kdtree_index(points[index_array[:median]],  indexs=indexs_sorted[:median],   depth=depth + 1),right_child=self._make_kdtree_index(points[index_array[median + 1:]], indexs=indexs_sorted[median + 1:],depth=depth + 1),split_axis=axis)def radius_search(self, point, radius, root=None,dist_func=lambda x, y: np.linalg.norm(x - y),results=None):"""Search the near nodes of the given point which are within givendistance radiusA list containing the n nearest nodes to the point within thedistance will be returned."""if root is None:# 初始化过程; 并且在查找过程中,root是一直会变的;# 不会造成bug,只有第一次会进入,最后的叶子节点不会进入root = self.tree# results 必须在这里再初始化一次,否则返回的也是它,那么它将被多次不断重复引用results = []# nodeDist = get_dist(self)nodeDist = dist_func(root.node, point)# 最后这里需要返回的是点的序号吧,而不是点,有点难if nodeDist < radius:# results.append((nodeDist,root.node))# results.append(root.node)results.append(root.ori_index)# get the splitting plane# split_plane = self.data[self.axis]split_plane = root.node[root.split_axis]# Search the side of the splitting plane that the point is in# 分别对应两种情况,一是 point[self.axis] - split_plane <= radius,# 也就是 | .  距离小于r, 需要到节点左边去搜索;# 另外一种是 split_plane - point[self.axis] <= radius, 也就是 . |# 距离小于r, 需要到节点右边去搜索;if point[root.split_axis] <= split_plane + radius:if root.left_child is not None:self.radius_search(point, radius, root=root.left_child, results=results)if point[root.split_axis] >= split_plane - radius:if root.right_child is not None:self.radius_search(point, radius, root=root.right_child, results=results)return results

但是实际运行的效果让我比较蛋疼,内存占用的确下去了,十万的点也不会报内存错误,但是。。。。

运行时间居然大大加长了(需要500秒),我把 kdtree 部分代码换成了 SciPy 的 kdtree,运行时间也同样加长了(需要200秒),合理的解释就是我的 DBSCAN 的部分就有效率问题。。。


另外,因为我是要处理点云数据,所以把数据的维度限定在了3维空间,如果你的不是,需要注意下;

KD tree 实现相关推荐

  1. PCL :K-d tree 2 结构理解

    K-d tree 基础思路:(先看之前的KNN思想,更容易理解) 导语:kd 树是一种二叉树数据结构,可以用来进行高效的 kNN 计算.kd 树算法偏于复杂,本篇将先介绍以二叉树的形式来记录和索引空间 ...

  2. PCL:k-d tree 1 讲解

    1.简介 kd-tree简称k维树,是一种空间划分的数据结构.常被用于高维空间中的搜索,比如范围搜索和最近邻搜索.kd-tree是二进制空间划分树的一种特殊情况.(在激光雷达SLAM中,一般使用的是三 ...

  3. k-d tree算法的研究

    By RaySaint 2011/10/12 动机 先前写了一篇文章<SIFT算法研究>讲了讲SIFT特征具体是如何检测和描述的,其中也提到了SIFT常见的一个用途就是物体识别,物体识别的 ...

  4. k-d tree树 近邻算法

    k-d树(k-dimensional树的简称),是一种分割k维数据空间的数据结构.主要应用于多维空间关键数据的搜索(如:范围搜索和最近邻搜索). 应用背景 SIFT算法中做特征点匹配的时候就会利用到k ...

  5. K-d tree 算法

    转载的原文链接:http://www.cnblogs.com/eyeszjwang/articles/2429382.html 已经写得非常好了,非常清晰.只是在原文的基础上增加了一点解释,方便大家理 ...

  6. kd tree python 搜索

    海量数据最近邻查找可以用kd tree 目前理解,kd tree需要的数据维度相同,否则会出问题 kd tree实现:https://github.com/stefankoegl/kdtree 下面是 ...

  7. BZOJ 3489: A simple rmq problem(K-D Tree)

    Time Limit: 40 Sec  Memory Limit: 512 MB Submit: 2579  Solved: 888 [Submit][Status][Discuss] Descrip ...

  8. k-d tree算法

    k-d树(k-dimensional树的简称),是一种分割k维数据空间的数据结构.主要应用于多维空间关键数据的搜索(如:范围搜索和最近邻搜索). 应用背景 SIFT算法中做特征点匹配的时候就会利用到k ...

  9. BZOJ4066:简单题(K-D Tree)

    Description 你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作: 命令 参数限制 内容 1 x y A 1<=x,y<=N,A是正整数 将格 ...

  10. BZOJ4520:[CQOI2016]K远点对(K-D Tree)

    Description 已知平面内 N 个点的坐标,求欧氏距离下的第 K 远点对. Input 输入文件第一行为用空格隔开的两个整数 N, K.接下来 N 行,每行两个整数 X,Y,表示一个点 的坐标 ...

最新文章

  1. Spring Cloud第七篇:高可用的配置中心
  2. C++成员变量指针和成员函数指针【The semantics of funcitons】
  3. 苹果:AMD yes!官方开售显卡模块,价格1.8万起
  4. Android。WebView加载UR请求使用Cookie储存User_Id记录用户是否登陆过
  5. 领跑BI赛道,永洪科技入选大数据创新排行榜
  6. 小物件之radio单选列表
  7. LeetCode MySQL 178. 分数排名(dense_rank连续排名)
  8. JS把命令式语句转换为表达式
  9. 速修复!21个漏洞影响60%的互联网邮箱服务器
  10. debian下apr-get isntall 出错提示用apt-get -f install问题
  11. 图像处理:透镜畸变及校正模型
  12. python 的库如何开发_Python开发者必备6个基本库
  13. 计算机桌面自设提示语,如何在电脑桌面便签上设置每周五自动弹窗提醒?
  14. Python常用第三方库大全, 值得收藏!
  15. 技术变现第一步:网站快速接入国际支付 Stripe
  16. linux网络编程tcp和udp基本函数调用过程及如何选择
  17. Java写的第一个小游戏(续)
  18. MySQL--数据库、表基本操作
  19. 《推背图》存在着什么样的秘密呢?
  20. JS---event事件

热门文章

  1. 小程序开发之路由navigateTo、reLaunch、redirectTo、switchTab及传值问题
  2. 怎么用计算机批改试卷,一人一天批改数千份卷子,看看你的试卷在老师面前的真实样子...
  3. java-jsp基于学生信息管理系统93nbx[独有源码]如何找到适合自己的毕业设计的指南
  4. 苹果电脑上NTFS硬盘无法写入怎么办?
  5. 三星即将完成android更新,三星Galaxy S9系列手机即将推送Android 10操作系统升级
  6. 【从入门到进阶】vim基础配置+ 常用插件(NERDTree, cscope, rainbow等)
  7. 手机无线服务器通讯录失败,手机通讯录云服务器
  8. RESTful风格的接口
  9. 现货交易技巧让投资事半功倍
  10. 商标侵权如何认定?侵犯商标权应该如何赔偿?