当前位置: 首页 > 知识库问答 >
问题:

如果点和多边形具有相同的最小边界框,则在多边形内查找点的空间索引

林念
2023-03-14

我有一个形状优美的多边形,代表洛杉矶市的边界。我在geopandas GeoDataFrame中还有一组约100万lat长的点,所有这些点都位于多边形的最小边界框内。其中一些点位于多边形本身内,但其他点不在多边形内。我只想保留洛杉矶边界内的那些点,由于洛杉矶的不规则形状,在其最小边界框内只有大约1/3的点在多边形本身内。

使用Python,如果点和多边形具有相同的最小边界框,识别这些点中哪些点位于多边形内的最快方法是什么?

我尝试使用geopandas和它的r树空间索引:

sindex = gdf['geometry'].sindex
possible_matches_index = list(sindex.intersection(polygon.bounds))
possible_matches = gdf.iloc[possible_matches_index]
points_in_polygon = possible_matches[possible_matches.intersects(polygon)]

这使用GeoDataFrame的r树空间索引来快速找到可能的匹配,然后找到多边形和那些可能匹配的确切交集。然而,由于多边形的最小包围盒与点集的最小包围盒相同,r-tree认为每个点都是可能的匹配。因此,使用r树空间索引不会比没有空间索引时运行得更快。这个方法很慢:需要~30分钟才能完成。

我还尝试将我的多边形划分为小的子多边形,然后使用空间索引来查找哪些点可能与每个子多边形相交。这种方法成功地找到了更少的可能匹配,因为每个子多边形的最小边界框比点集的最小边界框小得多。然而,将这组可能的匹配与我的多边形相交仍然只减少了大约25%的计算时间,所以这仍然是一个极其缓慢的过程。

有更好的空间索引方法吗?如果点和多边形具有相同的最小边界框,那么找到多边形内点的最快方法是什么?

共有2个答案

夏雅志
2023-03-14

举个小例子来重复一下这个问题

import pandas as pd
import shapely
import matplotlib.pyplot as plt

from matplotlib.collections import PatchCollection
from matplotlib.patches import Polygon
from shapely.geometry import Point
import seaborn as sns
import numpy as np

# some lon/lat points in a DataFrame
n = 1000000
data = {'lat':np.random.uniform(low=0.0, high=3.0, size=(n,)), 'lon':np.random.uniform(low=0.0, high=3.0, size=(n,))}
df = pd.DataFrame(data)

# the 'bounding' polygon
poly1 = shapely.geometry.Polygon([(1,1), (1.5,1.2), (2,.7), (2.1,1.2), (1.8,2.3), (1.6,1.8), (1.2,3)])
# poly2 = shapely.geometry.Polygon([(1,1), (1.3,1.6), (1.4,1.55), (1.5,1.2), (2,.7), (2.1,1.2), (1.8,2.3), (1.6,1.8), (1.2,3), (.8,1.5),(.91,1.3)])
# poly3 = shapely.geometry.Polygon([(1,1), (1.3,1.6), (1.4,1.55), (1.5,1.2), (2,.7), (2.1,1.2), (1.8,2.3), (1.6,1.8), (1.5,2), (1.4,2.5),(1.3,2.4), (1.2,3), (.8,2.8),(1,2.8),(1.3,2.2),(.7,1.5),(.66,1.4)])

# limit DataFrame to interior points
mask = [poly1.intersects(shapely.geometry.Point(lat,lon)) for lat,lon in zip(df.lat,df.lon)]
df = df[mask]

# plot bounding polygon
fig1, ax1 = sns.plt.subplots(1, figsize=(4,4))
patches  = PatchCollection([Polygon(poly1.exterior)], facecolor='red', linewidth=.5, alpha=.5)
ax1.add_collection(patches, autolim=True)

# plot the lat/lon points
df.plot(x='lat',y='lon', kind='scatter',ax=ax1)
plt.show()

在一个简单的多边形上调用一百万个点的intersects()不需要太多时间。使用Poly1,我得到以下图像。找到多边形内的lat/lon点需要不到10秒的时间。仅绘制边界多边形顶部的内部点如下所示:

In [45]: %timeit mask = [Point(lat,lon).intersects(poly1) for lat,lon in zip(df.lat,df.lon)]
1 loops, best of 3: 9.23 s per loop

Poly3更大更有趣。新图像如下所示,大约需要一分钟才能穿过瓶颈相交()线。

In [2]: %timeit mask = [poly3.intersects(shapely.geometry.Point(lat,lon)) for lat,lon in zip(df.lat,df.lon)]
1 loops, best of 3: 51.4 s per loop

因此,罪犯不一定是lat/lon点数。同样糟糕的是边界多边形的复杂性。首先,我推荐poly。simplify(),或者任何可以减少边界多边形中点的数量的操作(显然,不会对其进行剧烈更改)。

接下来,我建议考虑一些概率方法。如果一个点p被所有位于边界多边形内的点包围,则p也很有可能位于边界多边形内。一般来说,在速度和准确度之间有一点折衷,但也许这可以减少你需要检查的点数。以下是我尝试使用k-最近邻分类器的情况:

from sklearn.neighbors import KNeighborsClassifier

# make a knn object, feed it some training data
neigh = KNeighborsClassifier(n_neighbors=4)
df_short = df.sample(n=40000)
df_short['labels'] = np.array([poly3.intersects(shapely.geometry.Point(lat,lon)) for lat,lon in zip(df_short.lat,df_short.lon)])*1
neigh.fit(df_short[['lat','lon']], df_short['labels'])

# now use the training data to guess whether a point is in polygon or not
df['predict'] = neigh.predict(df[['lat','lon']])

给我这个图像。这并不完美,但是%timeit对于这个块只需要3.62秒(对于n=50000为4.39秒),而检查每个点大约需要50秒。

如果相反,我只想删除,比如说,有30%机会在多边形中的点(只是扔掉明显的违规者,并用手检查其余的)。我可以使用knn回归:

from sklearn.neighbors import KNeighborsRegressor
neigh = KNeighborsRegressor(n_neighbors=3, weights='distance')
#everything else using 'neigh' is the same as before

# only keep points with more than 30\% chance of being inside
df = df[df.predict>.30]

现在我只需要检查138000个点,如果我想使用intersects()检查每个点,那么检查速度会非常快。

当然,如果我增加邻居的数量或训练集的大小,我仍然可以得到更清晰的图像。这种概率方法的一些优点是:(1)它是算法,所以你可以把它扔到任何时髦的边界多边形上,(2)你可以很容易地上下调整它的精度,(3)它速度更快,伸缩性也很好(至少使用蛮力更好)。

像机器学习中的许多事情一样,可以有100种方法来做。希望这能帮助你找到有用的东西。这里还有一张带有以下设置的图片(使用分类器,而不是回归)。你可以看到越来越好了。

neigh = KNeighborsClassifier(n_neighbors=3, weights='distance')
df_short = df.sample(n=80000)
梅庆
2023-03-14

总结一下问题:当多边形的边界框与点集相同时,r-tree将每个点识别为一个可能的匹配,因此没有提供加速。当与大量点和具有大量顶点的多边形耦合时,相交过程非常缓慢。

解决方法:从这个geopandas r-tree空间索引教程中,使用一个四次例程将多边形分成子多边形。然后,对于每个子多边形,首先将其与点的r树索引相交,以获得一小部分可能的匹配,然后将这些可能的匹配与子多边形相交,以获得精确匹配的集合。这提供了约100倍的加速。

 类似资料:
  • 我有一个数据库,其中一个表(ca_licenses)是商业地址,另一个表是市议会区多边形的公共模式(ca_la_la_council)。 我运行此查询是为了将议会表中的地区号码放在企业地址表中: 我的问题是我总是得不到任何结果。两个几何列都是几何类型,SRID是4326。 示例ca_licenses数据:https://raw . githubusercontent . com/pour safe

  • 问题内容: 我对mysql,多边形的Geometric数据类型有一个典型的问题。 我有经度和纬度数组形式的面数据,例如: 我有一个经度和纬度坐标的点(顶点),例如: 现在,我想查找此顶点(点)是否在多边形内。我如何在php中做到这一点? 问题答案: 这是我从另一种语言转换为PHP的功能: 附加: 有关更多功能,我建议您使用此处提供的polygon.php类。使用顶点创建类,并以测试点作为输入调用该

  • 我有一组点(英国完整的邮政编码中心)。邮政编码与邮政编码扇区和邮政编码区之间存在等级关系。原来的扇区和区是毗连的。我希望推导出扇区和地区的近似边界,这样国家的任何部分都正好属于一个扇区和一个地区,所有得到的多边形理想地应该是连续的,而且(显然?)所有原点都应该在适当的多边形中。有没有合适的算法?更好的是,是否有一些适当的实现? 我想我一定解释得很差,因为我不认为这回答了我的问题。 让我们只谈部门,

  • 我在location _ table(point _ location geometry)中存储了位置,现在我在谷歌地图上绘制了一个多边形,并将该多边形(几何)传递给后端,我想找到该多边形内的所有位置。 当我将多边形从谷歌地图传递到后端时,这给了我随机的结果。它没有给我多边形内的所有点。它给了我甚至在多边形之外的点。 在 postgis 中准确查找多边形内所有点的正确方法是什么(也包括边界情况)

  • 问题内容: 前几天,我在Java中上了一堂课,以计算a 是否在多边形内。(和为,因为将是地理坐标)。 我知道Java具有该类,但是我必须使用and ,因为不允许使用,只能是整数:( 一旦在中完成多边形,就使用了方法(有了它),问题就解决了。 但是现在,我想导入到Android,问题就在这里,因为需要导入: 并且在Android中不存在awt,因此无法使用。 那么,是否有任何类似于had 方法的类?

  • 我正在寻找一种方法来创建一组多边形(rechtangles),沿着一条线在多个多边形中创建一组多边形(rechtangles),并将其水平隔开,如图所示。 我尝试生成点并将其用作多边形的中点,但问题是,通过创建等间距的点光栅,除了180度之外,不可能以任何其他方向旋转。 例子 给出了一个多多边形形状的对象和由宽度和高度以及每个多边形之间的垂直和水平间距定义的多边形。多边形应仅放置在多多边形内,且不