【问题标题】:How to efficiently filter rows from geopandas df that are not within the bounds of a shapely polygon?如何有效地过滤 geopandas df 中不在形状多边形范围内的行?
【发布时间】:2021-06-03 20:06:24
【问题描述】:

我有一个常规的 pandas 数据框,我像这样一次性转换为 geopandas

from shapely.geometry import Polygon, Point
import geopandas
geo_df = geopandas.GeoDataFrame(input_df, geometry=geopandas.points_from_xy(input_df.Longitude, input_df.Latitude))

我还有一个坐标列表,我可以将其转换为 Shapely Polygon,如下所示:

grid_polygon = Polygon(shape_coordinates)

然后我想过滤geo_df 中不在形状多边形grid_polygon 范围内的所有行。

我目前的方法是:

geo_df['withinPolygon'] = ""
withinQlist = []
for lon,lat in zip(geo_df['longitude'], geo_df['latitude']):
    pt = Point(lon, lat)
    withinQ = pt.within(grid_polygon)
    withinQlist.append(withinQ)
geo_df['withinPolygon'] = withinQlist
geo_df = geo_df[geo_df.withinPolygon==True]

但这是非常低效的。我认为有一种方法可以在不遍历每一行的情况下做到这一点,但我能够找到的大多数解决方案都不使用形状多边形进行过滤。有什么想法吗?

谢谢

【问题讨论】:

  • 使用 geo_df.apply() 应该比 for 循环稍快,但除非 Point 构造函数/检查可以向量化,否则您必须遍历所有行。
  • 谢谢 - 是的 apply 是一种选择,但我认为有一种更原生的方式来做到这一点 - 我相信这里的 Point 转换实际上是不必要的 - 必要的信息应该已经由 points_from_xy 编码在 geopandas df 的初始化中。我目前正在尝试使用逻辑 df[df.geometry.within(polygon)] 但仍在测试。

标签: python pandas geospatial geopandas shapely


【解决方案1】:

作为第一步,正如您在评论中已经提到的,您的代码可以简化如下:

import geopandas
geo_df = geopandas.GeoDataFrame(input_df, geometry=geopandas.points_from_xy(input_df.Longitude, input_df.Latitude)

geo_df_filtered = geo_df.loc[geo_df.within(grid_polygon)]

但有一些技术可以加快速度,具体取决于您拥有的数据类型和使用模式:

使用准备好的几何图形

如果您的多边形非常复杂,创建prepared geometry 将加快包含检查。 这将在开始时预先计算各种数据结构,加快后续操作。 (更多详情here。)

from shapely.prepared import prep

grid_polygon_prep = prep(grid_polygon)
geo_df_filtered = geo_df.loc[geo_df.geometry.apply(lambda p: grid_polygon_prep.contains(p))]

(不能像上面那样只做geo_df.loc[geo_df.within(grid_polygon_prep)],因为 geopandas 不支持这里准备好的几何图形。)

使用空间索引

如果您需要针对多个grid_polygons(而不仅仅是一个)对一组给定点运行包含检查,那么在这些点上使用空间索引是有意义的。 它会显着加快速度,尤其是当有很多点时。

Geopandas 为此提供了GeoDataFrame.sindex.query

match_indices = geo_df.sindex.query(grid_polygon, predicate="contains")
# note that using `iloc` instead of `loc` is important here
geo_df_filtered = geo_df.iloc[match_indices]

不错的博文,还有更多解释:https://geoffboeing.com/2016/10/r-tree-spatial-index-python/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-14
    • 2019-03-07
    • 1970-01-01
    • 2022-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多