基于R-Tree的地理空间数据分析加速

几年前,我正在做一个业余项目。我想创建一个 Web 应用程序,推荐当地的特色景点,例如咖啡馆、书店或隐藏的酒吧。我的想法是在地图上显示用户触手可及的所有兴趣点。我的数据集中有数十万个点,我必须巧妙地过滤用户给定范围内的数据点。最简单的方法是计算用户与每个兴趣点之间的距离,并丢弃指定范围之外的所有点。尤其是对于像我这样的大数据集,这种方法通常会导致较长的处理时间。

当然,一定有更好的方法,因为响应时间在交互式应用程序中很重要。这时我遇到了数据结构 R 树。这些树用于快速空间访问和搜索。使用 R 树,我能够快速隔离靠近用户位置的兴趣点并将其显示在地图上。这使我的 Web 应用程序的响应时间大大提高——只需增加四行代码!

在本文中,我解释了什么是 R 树以及它们的工作原理。前两节以纽约市的街道树木为例进行了说明。第三节演示了如何在 Python 中使用此数据结构来加速地理空间数据处理程序。

NSDT工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 - Three.js虚拟轴心开发包 - 3D模型在线减面 - STL模型在线切割 

1、分析纽约市的树木

假设我们被要求分析纽约市街区与树木健康状况之间是否存在相关性。纽约市开放数据门户提供了街道树木普查数据集,其中包括树种、直径、健康状况感知和每棵树的地理位置。

首先,我们要计算上东区的街道树木数量。下面的伪代码片段遍历数据集树木并检查树木是否位于 upper_east_side 边界内:

total_count, tree_count = 0, 0
for tree in trees:total_count += 1if upper_east_side.contains(tree):tree_count += 1
print_results(num_tests=total_count, num_trees=tree_count)
>>> Total number of trees tested: 683,788
>>> Number of trees in Upper East Side: 8,807

我们发现上东区大约有 9000 棵树。但是,为了达到这个目标,我们总共测试了 684000 棵树。下面的动画显示了我们测试的树木距离我们的目标街区有数英里远,因此很容易被忽略。但是,我们如何才能将远处的树木排除在昂贵的计算之外,以实现显着的性能提升?

我们几乎免费获得的一条信息是多边形的边界框(可以通过其节点的最小值和最大值确定)。此外,测试一个点是否落在矩形内很简单,只需要四个比较操作(该点必须大于或等于左下角,并且小于或等于右上角)。现在,假设 bounding_box 是一个数据集,其中包含上东区周围一个紧密矩形中的所有树木(在下一节中,我们将了解如何轻松获得这样的矩形)。考虑到这一点,得出:

total_count, tree_count = 0, 0
for tree in bounding_box:total_count += 1if upper_east_side.contains(tree):tree_count += 1
print_results(num_tests=total_count, num_trees=tree_count)
>>> Total number of trees tested: 10,768
>>> Number of trees in Upper East Side: 8,807

动画右侧显示我们现在只测试潜在候选者。这些是与多边形紧邻的树,即落在其边界框内的点。通过忽略远处的树,我们能够将测试次数从 684k 减少到 11k — 减少了 60 倍!在下一节中,我们将看到 R 树正是利用了这个想法。

(左)纽约市的所有树木都经过测试 | (右)仅测试上东区边界框内的树木

2、用于空间搜索的数据结构

R 树是一种基于树的数据结构,用于高效地创建空间索引。R 树通常用于快速空间查询或加速最近邻搜索 [1]。一种常见的用例可能是存储兴趣点(例如餐馆、加油站、街道等)的空间信息。借助 R 树,可以快速检索距离某个位置一定距离内的所有兴趣点。作为回报,这些结果可以显示在地图或导航系统中。

R 树的基本思想很简单:树的叶节点保存空间数据,而分支节点对应于包含其所有子节点的最小边界框。通过这种结构,R 树将空间划分为矩形,随着树的增长,矩形会变得更加细化。下面的示例说明了这一点:

(左)R 树将曼哈顿划分为多个矩形 (右)相应的树结构

查询 R 树中的矩形,即我们想要检索此搜索窗口中包含的所有数据。请记住,每个非叶节点都对应一个包含其所有子节点的边界框。要完成搜索查询,我们只需沿着树的分支行进,并沿着与给定矩形相交的路径行进,直到到达叶节点。这些叶节点(因此我们的数据点)包含在搜索矩形中并满足查询。下面的动画演示了我们可以通过忽略不符合搜索条件的整个分支来大大减少搜索操作的数量。

(左)与搜索矩形(红色)不相交的边界框(黑色)被迭代忽略 (右)

3、Python 中的 R 树

Python 包 Rtree 提供了 R 树数据结构的实现,并附带许多方便的功能,例如最近邻搜索、交集搜索或多维索引。

我们可以方便地使用 Python 的包管理器 pip 安装该包:

pip install Rtree

3.1 基础知识

在处理点或多边形等几何图形之前,我们先介绍一下 Rtree 包的基本用法:

from rtree import index
idx = index.Index()
bbox_0 = (0.0, 0.0, 1.0, 1.0) # (left, bottom, right, top)
bbox_1 = (3.0, 3.0, 6.0, 6.0)
idx.insert(0, bbox_0)
idx.insert(1, bbox_1)

索引模块帮助我们构建空间索引。此索引通过插入对象的边界框自动建立。边界框通过指定其左、下、右和上坐标来定义。请注意,我们将边界框与标识符一起插入(在上面的示例中为 0 和 1)。ID 将帮助我们在执行查询时识别边界框:

search_window = (-1.0, -1.0, 2.0, 2.0) # ex. 1
list(idx.intersection(search_window))
>>> [0]
search_window = (4.0, 4.0, 5.0, 5.0)   # ex. 2
list(idx.intersection(search_window))
>>> [1]
search_window = (0.0, 0.0, 6.0, 6.0)   # ex. 3
list(idx.intersection(search_window))
>>> [0, 1]
search_window = (1.01, 1.01, 2.0, 2.0) # ex. 4
list(idx.intersection(search_window))
>>> []

查询给定矩形的索引,同样由其左、下、右和上坐标指定。交集方法的结果是搜索窗口内包含的对象的 ID(示例 1-3)。如果搜索窗口超出索引中的数据范围,则结果为空(示例 4)。类似地,我们使用最近方法来查找给定搜索窗口的 k 个最近对象:

k = 1
search_window = (1.01, 1.01, 2.0, 2.0)
list(idx.nearest(search_window, k))
>>> [0]

3.2 使用点、线和多边形

在上一节中,我们了解了如何通过插入对象的边界框来构建索引。现在我们要继续使用点、线和多边形来表示这些对象。Shapely 包提供了一种在 Python 中处理此类几何图形的简单方法:

from shapely.geometry import Point, LineString, Polygon
point = Point(0, 0)
line = LineString([(1, 0), (2, 1)])
polygon = Polygon([(3, 0), (3, 1), (4, 1)])
idx = index.Index()
idx.insert(0, point.bounds)   # bounds: (0.0, 0.0, 0.0, 0.0)
idx.insert(1, line.bounds)    # bounds: (1.0, 0.0, 2.0, 1.0)
idx.insert(2, polygon.bounds) # bounds: (3.0, 0.0, 4.0, 1.0)

上面,我们首先创建一个点、一条线和一个多边形。接下来,将这些对象的边界框插入到使用 ID 0、1 和 2 的索引中。现在我们查询索引以获取不同的搜索窗口:

search_window = (0.0, 0.0, 0.5, 0.5)  # ex. 1
list(idx.intersection(search_window))
>>> [0]
search_window = (0.0, 0.0, 2.0, 1.0)  # ex. 2
list(idx.intersection(search_window))
>>> [0, 1]
search_window = (0.0, 0.0, 4.0, 2.0)  # ex. 3
list(idx.intersection(search_window))
>>> [0, 1, 2]
k = 1
search_window = (1.0, 0.0, 2.5, 1.5)  # ex. 4
list(idx.nearest(search_window, k))
>>> [1]

下图显示了几何形状和搜索窗口:

绿色:点、线和多边形。红色:搜索窗口

3.3 搜索上东区的所有树木

我们终于拥有了提取上东区所有树木所需的一切!我们将在下面介绍一段代码片段,但完整版本可在此处找到。

绿色:纽约市的树木。蓝色:上东区。橙色:上东区的边界框

首先,我们使用 GeoPandas 包加载所有必需的几何图形:

import geopandas as gpd
from rtree import index
df_trees = gpd.read_file('2015 Street Tree Census.geojson')
df_upper_east_side = gpd.read_file('upper_east_side.geojson')
geom_upper_east_side = df_upper_east_side.loc[0, 'geometry']

接下来,我们创建一个包含纽约市所有树木的 R 树索引:

idx = index.Index()
for id, geom in zip(df_trees.index, df_trees.geometry):idx.insert(id, geom.bounds)

现在,我们生成一个潜在候选者列表,即上东区边界框内的所有树木:

search_window = geom_upper_east_side.bounds
potential = list(idx.intersection(search_window))

最后,我们遍历所有潜在候选人,提取完全位于上东区的候选人:

trees = []
for tree in df_trees.loc[potential, 'geometry']:if geom_upper_east_side.contains(tree):trees.append(tree)print_results(num_data=len(df_trees), num_tests=len(potential), num_trees=len(trees))
>>> Total number of trees in dataset: 683,788
>>> Total number of trees tested: 10,768
>>> Number of trees in Upper East Side: 8,807

4、结束语

在本文中,我们了解了 R 树如何通过将底层空间划分为矩形来组织地理信息。这种结构使 R 树在空间查找方面非常快。在我们的纽约市街道树示例中,使用 R 树将操作数量减少了 60 倍。我们还了解了如何在 Python 中使用 R 树。在我们的示例中,仅用四行代码就实现了加速:初始化索引(1 行)、构建索引(2 行)以及使用交集函数查找附近的候选对象(1 行)。

那么为什么不到处都使用 R 树呢?虽然我们通过减少搜索操作数量来节省时间,但构建索引会浪费时间。对于后者,我们实际上必须遍历整个数据集。这使得 R 树不适用于只需要少量搜索的应用程序或索引经常更改的应用程序(因为树重新平衡)。

自 1984 年 Antonin Guttman 发明 R 树以来,R 树已经取得了长足的进步。如今,R 树已应用于各种应用,例如计算机图形学 、视频游戏 、交通控制系统 ,最突出的是空间数据管理数据库 。也许,你下一次进行地理空间数据分析时,R 树也会派上用场!


原文链接:用R树加速空间数据分析 - BimAnt

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

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

相关文章

一键生成insert,update,delete,的mybatis sql 语句

由于最近写增删改查,对与开发来说,编写一个insert和update 语句是十分耗时耗力的,因为有大量的字段要复制粘贴。粘贴完还要去比对一下有没有漏粘的,很耗费精力,于是就想着写一个sql,通过手动指定哪张表&…

二、C#基本语法

C#是一种面向对象的编程语言。在面向对象的程序设计方法中,程序由各种相互交互的对象组成。相同种类的对象通常具有相同的类型,或者说,是相同的class中。 例如,以rectangle(矩形)对象为例。它具有length和…

STM32Cube配置STM32F072C8T6的CAN总线说明

目录 1. 引脚配置2. 时钟配置3. 代码添加 1. 引脚配置 2. 时钟配置 CAN配置 波特率计算:500K 48 / (431)*12 48 / 96 使能中断,很关键,否则CAN无法发送。 3. 代码添加 添加滤波器使能、接收中断使能、CAN使能&…

打造基于大模型的AI产品

我要飞往印度进行短暂旅行,因此花了一个小时的时间处理在线签证申请流程。完成后,由于我现在知道涉及的内容,我向 ChatGPT 4o 询问了相关问题。这些观点中的大多数都是部分或完全错误的。 NSDT工具推荐: Three.js AI纹理开发包 - …

微信小程序开发系列(三十五)·自定义组件的属性properties

微信小程序开发系列(三十四)自定义组件的创建、注册以及使用(数据和方法事件的使用)_wx小程序组件开发-CSDN博客 目录 1. 组件的属性 2. 组件的使用 3. 细节描述 1. 组件的属性 Properties是指组件的对外属性,主…

Ms08067安全实验室成功实施多家业务系统渗透测试项目

点击星标,即时接收最新推文 近日,Ms08067安全实验室针对多家公司重要系统实施渗透测试项目。公司网络信息系统的业务应用和存储的重要信息资产均较多,存在网络系统结构的复杂性和庞杂等特点,使得公司网络信息系统面临一定风险。项…

顺安蜘蛛池四川官网下载

baidu搜索:如何联系八爪鱼SEO? baidu搜索:如何联系八爪鱼SEO? baidu搜索:如何联系八爪鱼SEO? 虽然影视泛目录很火,但超度站群版本自出现以来-直流量稳定,可惜这两年起站全靠域名。但话说回来,咱不能否认,只要用的域名好,做啥泛目录都有好…

【第11章】别人的工作流,如何使用和调试(上)?(2类必现报错/缺失节点/缺失模型/思路/实操/通用调试步骤)ComfyUI基础入门教程

经过前面章节的学习,相信大家对于工作流是什么?如何搭建?怎么使用基础的工作流?已经很清楚了。 那么,接下来的课程,我们会上一点难度, 并且更接近实战状态了。 这节课,我们就用一套从“文本 - 静帧 - 视频”的AI短片全流程工作流,讲一下,网络上下载的工作流,需要如…

树与图的深度优先遍历——AcWing.846树的重心

树与图的深度优先遍历 定义 从图的某个顶点出发,沿着一条路径尽可能深地访问图中顶点。 运用情况 图的连通性判断。寻找特定路径或回路。 注意事项 要标记已访问的节点,以避免重复访问导致死循环。对于有向图和无向图可能需要不同的处理。 解题思…

C++ Primer Plus第五版笔记(p201-250)

第六章 函数(下) 在含有return语句的循环后面应该也有一条return语句 不要返回局部对象的引用或指针,当函数结束时临时对象占用的空间也就随之释放掉了,所以两条return语句都指向了不再可用的内存空间。 如果函数返回指针、引用…

排序(2)【选择排序】【快速排序】

一.选择排序 选择排序就是选择一个数组的最大的数字或者最小的数字,放在一整个数组的最后或者开头的位置。 1.选择排序的实现 我们可以对选择排序进行一些加强,普通的选择排序是选择最小的数,然后进行交换。这个加强之后就是我们既要选择出…

从ES的JVM配置起步思考JVM常见参数优化

目录 一、真实查看参数 (一)-XX:PrintCommandLineFlags (二)-XX:PrintFlagsFinal 二、堆空间的配置 (一)默认配置 (二)配置Elasticsearch堆内存时,将初始大小设置为…

ElasticSearch + kibana:类型声明

当我们使用 kibana 创建索引时,如果不申明数据类型,默认字符串赋予 text类型,如下图所示 接下来我们继续创建多条数据如下: 下面我们来检索下: 通过以上两个案例我们发现,使用 match 模糊查询 li-3 明明…

别再问别人了,这是小白都能懂的拓扑图指南

号主:老杨丨11年资深网络工程师,更多网工提升干货,请关注公众号:网络工程师俱乐部 上午好,我的网工朋友。 老杨的网工交流群里经常会有这种现象: 一群小伙伴在问各类型拓扑图的问题,怎么设计&…

monitor-zabbix

监控体系理论 学习本篇文章,了解运维监控系统的前世今生 zabbix官网仓库地址 zabbix官网 https://www.zabbix.com/cn/zabbix官网仓库地址 http://repo.zabbix.com/zabbix/ http://repo.zabbix.com/zabbix/4.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_…

Hi3861 OpenHarmony嵌入式应用入门--基于HI-12F开发板烧写程序

首先需要一个开发板,我已经在嘉立创上进行了开源,基于安信可hi-12f模块的开发板,集成了两个按键,一个三色灯,一个滑动变阻器,可外接一个0.96寸液晶。 【HI-12F】基于安信可hi-12f模块的开发板 - 嘉立创EDA…

借助Aspose.Email,使用 C# .NET 创建 PST 文件并填充内容

PST(个人存储表)文件是管理 Outlook 数据的重要组成部分,方便存储电子邮件、联系人、日历和其他项目。在 C# .NET 开发领域,创建和管理存储文件的过程对于各种应用程序至关重要。 在本文中,我们将探讨如何使用 C# .NE…

内窥镜窄带光

文章目录 NBI相关信息 NBI相关信息 第一不知道哪家有这个技术? 第二直接搜索找不到相关信息 第三只能搜企业官网 搜集到的与NBI,相关的信息如下 英美达医疗公司 https://www.innermed.com/index.php/gongsixinwen/139.html 新光维医疗公司 官网页面…

【Spring】1. Maven项目管理

📚博客主页:爱敲代码的小杨. ✨专栏:《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 |《MySQL探索之旅》 |《Web世界探险家》 ❤️感谢大家点赞👍🏻收藏⭐评论✍🏻,您的三连就是我持续更…

【无标题】Pycharm执行报错

file 读取未指定utf-8编码,加上就好了 疑问:为什么 有的电脑可以直接跑呢?该电脑、Pycharm、工程,已经做了修改设置默认值,但是到新的电脑上,就需要重新设置,所以 file 读、写,最好…