如何用GeoPandas与Pandas优化千万级数据的区域匹配函数?
优化方案:用空间索引+向量化空间连接处理大规模数据
核心问题分析
你的代码采用双层嵌套循环,对每个订单点遍历所有多边形执行within判断,时间复杂度为O(N*M)(N为订单数,M为多边形数),面对1000万级别的数据时,这种逻辑会导致运行效率极低,必须通过空间索引+向量化操作将复杂度降至接近O(N log M)。
具体优化步骤
1. 统一数据格式与坐标系
先将订单数据转换为GeoDataFrame格式,同时确保多边形数据(geo_df)与订单数据使用相同的坐标系(例如WGS84的EPSG:4326,或投影坐标系EPSG:3857——后者的空间计算速度更快)。
2. 利用空间索引快速过滤
GeoPandas会自动为GeoDataFrame的geometry列构建基于rtree的空间索引,借助该索引可快速筛选出可能包含目标点的多边形,无需遍历全部多边形。
3. 向量化空间连接实现匹配
GeoPandas的geopandas.sjoin()方法是向量化实现的,底层通过空间索引加速,能直接完成点与多边形的批量匹配,效率比循环高出数个数量级。
4. 超大规模数据的分块处理(可选)
若1000万行数据一次性加载会超出内存,可分批次处理订单数据,每批次处理一部分后再合并结果。
优化后的代码示例
import geopandas as gpd import pandas as pd def get_district_name(geo_df: gpd.GeoDataFrame, ship_df: pd.DataFrame, col_name: str, frac: float=0.65) -> pd.DataFrame: # 1. 采样订单数据 sample_ship = ship_df.sample(frac=frac, replace=False, random_state=42).reset_index(drop=True) # 2. 将订单数据转为GeoDataFrame,注意经纬度顺序:经度对应x,纬度对应y sample_ship_geo = gpd.GeoDataFrame( sample_ship, geometry=gpd.points_from_xy(sample_ship['address_longitude'], sample_ship['address_latitude']), crs=geo_df.crs # 强制与多边形数据坐标系一致 ) # 3. 空间连接:匹配点所在的多边形,how='left'保留所有订单记录 joined = gpd.sjoin(sample_ship_geo, geo_df[[col_name, 'geometry']], how='left', op='within') # 4. 整理结果列 joined = joined.rename(columns={col_name: 'municipal_district_name'}) # 移除空间连接产生的冗余列,保留原订单数据列与匹配的区域名 result = joined.drop(columns=['geometry', 'index_right']) return result
额外优化建议
- 坐标系转换:若当前使用WGS84(EPSG:4326),可转换为投影坐标系(如对应区域的UTM分区或EPSG:3857),投影坐标系下的空间计算速度更快、精度更高。
- 多边形预处理:确保
geo_df的geometry无自相交、空洞等无效问题,可通过geo_df.geometry = geo_df.geometry.buffer(0)修复无效多边形。 - 内存优化:处理超大规模数据时,仅保留经纬度与必要业务列;若内存不足,用
pd.read_csv(chunksize=100000)分块读取订单数据,逐块处理后合并结果。
内容的提问来源于stack exchange,提问作者rg4s
相关产品推荐
相关产品推荐

