我有两个 GeoDataFrames gdf_point:
Unnamed: 0 latitude longitude geometry 0 0 50.410203 7.236583 POINT (7.23658 50.41020) 1 1 51.303545 7.263082 POINT (7.26308 51.30354) 2 2 50.114965 8.672785 POINT (8.67278 50.11496)
和gdf_poly:
Unnamed: 0 Id geometry 0 0 301286 POLYGON ((9.67079 49.86762, 9.67079 49.86987, ... 1 1 302258 POLYGON ((9.67137 54.75650, 9.67137 54.75874, ... 2 2 302548 POLYGON ((9.66808 48.21535, 9.66808 48.21760, ...
我想匹配 gdf_point 中的点是否包含在 gdf_poly 的任何多边形中,如果是,我希望将该多边形的 Id 添加到 gdf_point 的相应行。
这是我当前的代码:
COUNTER = 0 def f(x, gdf_poly, df_new_point): global COUNTER for row in gdf_poly.itertuples(): geom = getattr(row, 'geometry') id = getattr(row, 'Id') if geom.contains(x): print('True') df_new_point.loc[COUNTER, 'Id'] = id COUNTER = COUNTER + 1 df_new_point = gdf_point gdf_point['geometry'].apply(lambda x: f(x, gdf_poly, df_new_point))
它能正常工作,并能完成我想要的功能。但问题是它的速度太慢了,处理 10k 行数据需要大约 50 分钟(多线程是未来的选项),我希望它能够处理数百万行数据。一定有更好更快的方法来做到这一点。谢谢你的帮助。
你现在的代码使用了 apply 和 for 循环,这在处理大量数据时效率较低。可以通过以下几种方法提升性能,尤其是在处理几百万行数据时。
apply
for
geopandas
sjoin
geopandas 提供了一个空间连接(spatial join)的方法,叫做 sjoin,可以直接用于找出点是否位于多边形内。通过空间连接,你可以避免循环,提高效率。
你可以使用 geopandas.sjoin 来匹配点是否在多边形内,并将多边形的 Id 添加到点的 GeoDataFrame 中。
geopandas.sjoin
Id
import geopandas as gpd # 假设你已经有了 gdf_point 和 gdf_poly 数据 # 确保投影坐标一致 gdf_point = gdf_point.set_crs("EPSG:4326", allow_override=True) # 或者根据需要更改 EPSG 代码 gdf_poly = gdf_poly.set_crs("EPSG:4326", allow_override=True) # 使用空间连接(sjoin)进行查询 gdf_point_with_id = gpd.sjoin(gdf_point, gdf_poly, how="left", op='within') # 结果会在 gdf_point_with_id 中包含每个点所属的多边形的 'Id'(如果点在多边形内) print(gdf_point_with_id[['latitude', 'longitude', 'Id']])
gdf_point
gdf_poly
how='left'
op='within'
gdf_point_with_id
如果数据集非常大(例如数百万行),可能需要进一步优化性能。以下是一些可能的优化方法:
rtree
pip install rtree
# 例如,分批处理 batch_size = 100000 for start in range(0, len(gdf_point), batch_size): batch = gdf_point.iloc[start:start+batch_size] batch_with_id = gpd.sjoin(batch, gdf_poly, how="left", op='within') # 处理每批数据 print(batch_with_id[['latitude', 'longitude', 'Id']])
如果你还需要并行化,Dask 是一个可以帮助加速大规模数据处理的库。你可以将数据分块处理,并在多个核心上并行执行。
Dask
pip install dask
然后,你可以使用 Dask 来处理大型 GeoDataFrame,并通过多线程/多进程并行化计算。
GeoDataFrame
使用这些方法,你将能够以更高效的方式完成大规模空间查询,处理百万行数据时显著提升性能。