KDTree空间搜索算法学习

目录

  • KDTree(K-Dimensional Tree)原理
  • 步骤
    • 空间索引建立例子[^1]
    • 回溯搜索例子[^2]
  • 相关包
  • 案例[^3]
    • 数据
    • KDTree 识别轨道衔接出行
    • 轨道衔接单车骑行范围分析
    • 结果保存

KDTree(K-Dimensional Tree)原理

将需要匹配的 K 维空间点建立 K 维树空间索引,在近邻匹配时,输入的点在树中快速检索,即可找到最近邻的点。
在建立空间索引二维树时,算法复杂度介于 O ( l o g 2 n ) O(log_2n) O(log2n) O ( n ) O(n) O(n)之间。

  • 最好的情况下,每次插入点能均匀分割剩余点,算法复杂度为 O ( l o g 2 n ) O(log_2n) O(log2n)
  • 最坏的情况下,每次插入点其余点都在一个字空间中,树的深度为n,算法复杂度为 O ( n ) O(n) O(n)

步骤

  1. 空间索引建立
    • 给定或选择中心节点
    • 依次从各维度分割
    • 按照层次插入点,建立空间索引
      KDTree索引
  2. 最近邻搜索
    • 给定数据点,查询与其距离最近的点
    • 从根节点开始依次向下搜索,进行深度优先遍历(二分搜索),直到与待查询点处于同一子空间的叶子结点
    • 回溯搜索路径、判断路径上其它子节点空间中,是否可能有距离更近的点
      • 如过有可能,跳转到其他子空间去搜索,将其他子节点加入搜索路径
      • 待查询点为圆心,以待查询点到叶子结点的距离为半径作圆,如果不相交则不必去其他字空间搜索
    • 重复过程,直到搜索路径为空
      KDTree搜索

空间索引建立例子1

  • 二维样例:{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)}
  • 根据x轴中位数,选择中心点为(7,2)
  • 首先在 x 轴维度上,比较其余点和中心点的大小,划分双支
    • 左支:{(2,3),(5,4),(4,7)}
    • 右支:{(9,6),(8,1)}
  • 更新分割轴y轴
  • 确定子节点
    • 左节点
      • 在左支中找到y轴的中位数(5,4)
      • 左支数据更新为{(2,3)},右支数据更新为{(4,7)}
    • 右节点
      • 在右支中找到y轴的中位数(9,6)
      • 左支数据更新为{(8,1)},右支数据为null。
  • 更新分割轴x轴
    • 确定(5,4)的子节点
      • 左节点:由于只有一个数据,所以,左节点为(2,3)
      • 右节点:由于只有一个数据,所以,右节点为(4,7)
    • 确定(9,6)的子节点

回溯搜索例子2

回溯搜索

相关包

sklearn、SciPy、TransBigData、BioPython 中都提供了 KDTree 相关算法接口

  • class sklearn.neighbors.KDTree(X, leaf_size=40, metric=‘minkowski’, **kwargs)
    sklearn.neighbors.KDTree

  • class scipy.spatial.KDTree(data, leafsize=10, compact_nodes=True, copy_data=False, balanced_tree=True, boxsize=None)
    scipy.spatial.KDTree

  • transbigdata.ckdnearest(dfA_origin, dfB_origin, Aname=[‘lon’, ‘lat’], Bname=[‘lon’, ‘lat’])

  • classBio.KDTree.KDTree.KDTree(dim, bucket_size=1)

案例3

数据

共享单车数据

BIKE_IDDATA_TIMELOCK_STATUSLONGITUDELATITUDE
单车ID数据采集时间单车开关锁状态GPS经度GPS维度

共享单车数据

metro_station.csv地铁站数据

KDTree 识别轨道衔接出行

#定义函数,用cKDTree匹配点与点,点与线
import numpy as np
from scipy.spatial import cKDTree
import itertools
from operator import itemgetter
#定义KDTree的函数
def ckdnearest(dfA_origin,dfB_origin,Aname = ['slon','slat'],Bname = ['lon','lat']):gdA = dfA_origin.copy()gdB = dfB_origin.copy()from scipy.spatial import cKDTree#为gdB表的点建立KDTreebtree = cKDTree(gdB[Bname].values)#在gdB的KDTree中查询gdA的点,dist为距离,idx为gdB中离gdA最近的坐标点dist,idx = btree.query(gdA[Aname].values,k = 1)#构建匹配的结果gdA['dist'] = distgdA['index'] = idxgdB['index'] = range(len(gdB))gdf = pd.merge(gdA,gdB,on = 'index')#计算import CoordinatesConvertergdf['dist'] = CoordinatesConverter.getdistance(gdf[Aname[0]],gdf[Aname[1]],gdf[Bname[0]],gdf[Bname[1]])return gdf#读取轨道站点数据
metro_station = pd.read_csv(r'data/metro_station.csv')
metro_station = metro_station.drop_duplicates(subset= 'stationnames')
metro_station = metro_station[['stationnames','lon','lat']]#匹配起点最近的地铁站
metro_station.columns = ['o_station','o_lon','o_lat']
data_move_metro = ckdnearest(data_move_cleaned,metro_station,Aname = ['slon','slat'],Bname = ['o_lon','o_lat'])
data_move_metro = data_move_metro.rename(columns = {'dist':'o_dist'})#匹配终点最近的地铁站
metro_station.columns = ['d_station','d_lon','d_lat']
data_move_metro = ckdnearest(data_move_metro,metro_station,Aname = ['elon','elat'],Bname = ['d_lon','d_lat'])
data_move_metro = data_move_metro.rename(columns = {'dist':'d_dist'})
data_move_metro.iloc[:2].T    #筛选距离地铁站100米范围内的出行数据
data_move_metro = data_move_metro[(data_move_metro['o_dist']<100)|(data_move_metro['d_dist']<100)]
data_move_metro.iloc[:2].T

轨道衔接单车骑行范围分析

#选取某站点
station = '同济大学'
#提取地铁站衔接出行的另一端点分布
tmp1 = data_move_metro[(data_move_metro['o_station']==station)&(data_move_metro['o_dist']<=100)][['elon','elat']]
tmp2 = data_move_metro[(data_move_metro['d_station']==station)&(data_move_metro['d_dist']<=100)][['slon','slat']]
tmp1.columns = ['lon','lat']
tmp2.columns = ['lon','lat']
points = pd.concat([tmp1,tmp2])#转换为GeoDataFrame
points = geopandas.GeoDataFrame(points)
points['geometry'] = geopandas.points_from_xy(points['lon'],points['lat'])points.plot()

站点骑行衔接需求点分布

#读取轨道站点数据
metro_station = pd.read_csv(r'data/metro_station.csv')
metro_station = metro_station.drop_duplicates(subset= 'stationnames')
#提取这个站点的记录
thisstop = metro_station[metro_station['stationnames']==station]
thisstop = geopandas.GeoDataFrame(thisstop)
thisstop['geometry'] = geopandas.points_from_xy(thisstop['lon'],thisstop['lat'])
thisstop
stationnameslinenamelonlatgeometry
同济大学地铁10号线(新江湾城-虹桥火车站)121.50206731.284578POINT (121.50207 31.28458)
#取得这个站点的位置
lon_thisstop = thisstop['lon'].iloc[0]
lat_thisstop = thisstop['lat'].iloc[0]
#确定显示范围
bounds = [lon_thisstop-0.03,lat_thisstop-0.03,lon_thisstop+0.03,lat_thisstop+0.03]import matplotlib.pyplot as plt
fig = plt.figure(1,(6,5),dpi = 300)
ax = plt.subplot(111)
plt.sca(ax)
#加载底图
import transbigdata as tbd
#绘制底图
tbd.plot_map(plt,bounds,zoom = 14,style = 4)
points.plot(ax = ax,markersize = 1)
#标注地铁站点
thisstop.plot(ax = ax,c = 'red',markersize = 8,zorder = 2,label = station+'地铁站')
plt.legend()
#设置显示范围
plt.axis('off')
ax.set_xlim(bounds[0],bounds[2])
ax.set_ylim(bounds[1],bounds[3])
plt.show()

共享单车衔接需求分布

#剔除距离过远的点,否则核密度估计可能会出错
points = points[(points['lon']>bounds[0])&
(points['lat']>bounds[1])&
(points['lon']<bounds[2])&
(points['lat']<bounds[3])]import matplotlib.pyplot as plt
fig = plt.figure(1,(6,5),dpi = 300)
ax = plt.subplot(111)
plt.sca(ax)
#加载底图
import transbigdata as tbd
bounds = [lon_thisstop-0.05,lat_thisstop-0.05,lon_thisstop+0.05,lat_thisstop+0.05]
#绘制底图
tbd.plot_map(plt,bounds,zoom = 13,style = 4)
#标注地铁站点
thisstop.plot(ax = ax,c = 'blue',markersize = 8,zorder = 2,label = station+'地铁站')
plt.legend()
#设置显示范围
plt.axis('off')
ax.set_xlim(bounds[0],bounds[2])
ax.set_ylim(bounds[1],bounds[3])
plt.title(station+'地铁站共享单车衔接范围')
#设置色标
import matplotlib
cmapname = 'autumn_r'
cmap = matplotlib.cm.get_cmap(cmapname)
cax = plt.axes([0.08, 0.4, 0.02, 0.3])
#色标的标题
plt.title('核密度')
import seaborn as sns
#绘制二维核密度图
sns.kdeplot(points['lon'],points['lat'],#指定x与y坐标所在的列data = points,alpha = 0.8,#透明度gridsize = 180, #绘图精细度,越高越慢bw = 0.1,    #高斯核大小(经纬度),越小越精细cmap = cmap, #定义colormapax = ax, #指定绘图位置shade=True, #等高线间是否填充颜色shade_lowest=False,#最底层不显示颜色cbar=True, #显示colorbarcbar_ax=cax,#指定colorbar位置zorder = 1 #控制绘图顺序,使其不会挡住地铁站点)
plt.show()

共享单车核密度可视化

结果保存

points[['lon','lat']].to_csv(r'data/bicycle_connection_points.csv',index = None)

bicycle_connection_points.csvbicycle_connection_points


  1. KD-Tree原理详解 ↩︎

  2. KD-Tree详解: 从原理到编程实现 ↩︎

  3. 《交通时空大数据分析、挖掘与可视化(Python版)》 ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/7727.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据分析必备:一步步教你如何用numpy改变数据处理(6)

介绍&#xff1a; NumPy 广播&#xff08;Broadcasting&#xff09;是指当两个形状不同的数组进行运算时&#xff0c;NumPy 有能力灵活地改变其中某个&#xff08;些&#xff09;数组的形状从而使得运算可以正常进行。 广播的规则主要包括以下几点&#xff1a; 当一个数组是一个…

互联网十万个为什么之什么是云计算

云计算是一种通过互联网提供计算资源和服务的技术。它允许用户随时随地访问和使用云平台上的数据、软件和硬件资源。在数字化时代&#xff0c;互联网已经成为基础设施。云计算使得数据中心能够像一台计算机一样去工作。通过互联网将算力以按需使用、按量付费的形式提供给用户&a…

Linux进程地址空间第三讲

至今为止&#xff0c; 我们所学到的大多数的知识&#xff0c; 包括语言&#xff0c; 数据结构&#xff0c; 动静态库等等的 都是在下面这3G&#xff0c; 也就是用户空间里的(进程等待&#xff0c; 信号之类的与内核有关的是在上面那1G里的) 所以对于我们来说&#xff0c; 我们…

【数据结构】链表经典OJ题目练习(2)

面试题 02.02. 返回倒数第 k 个节点 - 力扣&#xff08;LeetCode&#xff09; 思路1&#xff1a;先计算出链表的长度&#xff0c;在将链表中的值存在数组中&#xff0c;在返回第k个节点。 思路2&#xff1a;利用快慢指针&#xff0c;先让快指针走k步&#xff0c;在让快慢指针分…

多模态大模型学杂了能力反下降?新研究:MoE+通用专家解决冲突

微调&#xff0c;能让通用大模型更加适配具体的行业应用。 但现在&#xff0c;研究人员们却发现&#xff1a; 对多模态大模型做“多任务指令微调”&#xff0c;大模型可能会“学得多错得多”&#xff0c;因为不同任务之间的冲突&#xff0c;导致泛化能力下降。 △多模态指令微…

杭州恒生面试,社招,3年经验

你好&#xff0c;我是田哥 一位朋友节前去恒生面试&#xff0c;其实面试问题大部分都是八股文&#xff0c;但由于自己平时工作比较忙&#xff0c;完全没有时间没有精力去看八股文&#xff0c;导致面试结果不太理想&#xff0c;HR说节后通知面试结果&#xff08;估计是凉了&…

【软件测试】接口自动化测试面试题及详细答案

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

【算法】数字接龙 走迷宫问题的一般处理思路

前言 其实走迷宫就是一个普普通通的深搜回溯嘛&#xff0c;但是我之前做的很多题都是在一个二维的地图上&#xff0c;只能上下左右四个方向走迷宫&#xff0c;在做数字接龙这道题的时候&#xff0c;相当于可以往8个方向走&#xff0c;虽然逻辑上不变&#xff0c;但按照我之前的…

[Maven]IDEA报错-xxx is referencing itself

在IDEA中&#xff0c;执行 mvn clean时报错xxx is referencing itself。 解决方案&#xff1a;https://stackoverflow.com/questions/64246267/maven-error-using-intellij-is-referencing-itself 具体做法&#xff1a;采用上图第二条&#xff0c;将父模块pom文件中的对子模块…

1天搞定SpringBoot+Vue全栈开发 (7)Axios网络请求

1.Axios的使用 Axios中文文档 | Axios中文网Axios 是一个基于 promise 的网络请求库&#xff0c;可以用于浏览器和 node.jshttps://www.axios-http.cn/ 2.与vue整合 App.vue: <template><div id"app"><Moviev-for"movie in movies":key&qu…

【mobx-入门与思考】

介绍 mobx 是 nodejs生态中的框架&#xff0c; 主要用于做状态管理&#xff0c;可以监控变量状态的变化。 nodejs中除了mobx&#xff0c;还有个redux&#xff0c;也是做状态管理的&#xff0c;都是比较成熟的框架&#xff0c;二者的选择可以参考 【nodejs状态管理: Redux VS M…

mac电脑如何安装python及环境搭建

&#xff08;1&#xff09;进入官网&#xff1a;Download Python | Python.org&#xff0c;根据自己电脑选择python (2)这里我选择的是mac,点击&#xff1a;macos&#xff0c;选择最近版本并点击进入 (3)选择mac版本&#xff1a; (4)点击就可以进入下载&#xff1a; (5)下载好之…

京东工业优选商品详情API接口:解锁高效工业采购新体验

京东工业优选的商品详情API接口&#xff0c;允许开发者通过程序化的方式&#xff0c;快速获取平台上的商品详细信息。这些详细信息包括但不限于商品名称、价格、规格、库存、图片、评价等&#xff0c;为企业提供全方位的商品信息查询服务。 二、API接口的主要功能 实时查询&a…

Baidu Comate——您的智能编码伙伴

文章目录 1.Baidu Comate智能编码助手简介2.Baidu Comate安装使用3.查看Comate插件功能4.Baidu Comate基础功能介绍✨注释生成代码✨实时续写✨函数注释✨行间注释✨代码解释✨单元测试生成✨代码优化✨技术问答 5.使用体验结语 1.Baidu Comate智能编码助手简介 ✨Baidu Comat…

电脑装了两个Win10系统,怎么修改其名称方便识别?

前言 有小伙伴在上一期的双系统教程上留言说怎么修改双系统引导时候显示的名称 不然看起来两个系统好像都没啥分别&#xff0c;如果是Windows10Windows11的方案还好说&#xff0c;但如果是两个Windows10或者是两个Windows11&#xff0c;有时候还真的很不好分辨。 万一想要启动…

Candance画运算放大器

根据拉扎维《模拟CMOS集成电路设计》第九章第一个放大器进行搭建电路图。 此电路图中两个NMOS栅极互联是因为NMOS的衬底要接片上最低电压。所以要两个互联并接到最低点。 因为两条支路上的器件都是一样的&#xff0c;所以这两条路平分idc的直流电流。 测试的时候要加上下图这两…

【Ajax零基础教程】-----第一课 Ajax简介

一、什么是ajax ajax即 Asynchronous javascript And XML (异步 javaScript 和 XML) 是一种创建交互式&#xff0c;快速动态应用的网页开发技术&#xff0c;无需重新加载整个网页的情况下&#xff0c;能够更新页面局部数据的技术。 二、为什么使用Ajax 通过在后台与服务器进行少…

天锐绿盾 | 办公加密系统,源代码防泄密、源代码透明加密、防止开发部门人员泄露源码

天锐绿盾作为一款专注于数据安全与防泄密的专业解决方案&#xff0c;它确实提供了针对源代码防泄密的功能&#xff0c;帮助企业保护其核心的知识产权。 PC地址&#xff1a; https://isite.baidu.com/site/wjz012xr/2eae091d-1b97-4276-90bc-6757c5dfedee 以下是天锐绿盾可能采…

值得收藏!修复Windows 10/11中找不到输出或输入设备的五种方法

序言 这篇文章主要关注处理声音输出/输入设备未发现的问题。它提供了许多可行的方法,帮助了许多Windows用户。阅读以下内容以找到你的解决方案。 最近,我将Windows 10更新到21H2,发现我的音频无法工作。当我把鼠标放在任务栏上的声音图标(上面有一个十字图标)上时,它会…

6.Nginx

Nginx反向代理 将前端发送的动态请求有Nginx转发到后端服务器 那为何要多一步转发而不直接发送到后端呢&#xff1f; 反向代理的好处&#xff1a; 提高访问速度&#xff08;可以在nginx做缓存&#xff0c;如果请求的是同样的接口地址&#xff0c;这样就不用多次请求后端&#…