替代Pandas apply的更优方案:点到海岸线距离计算提速
点到最近海岸线距离计算的性能优化问题
需求与数据说明
- 核心需求:计算每个点到最近海岸线的距离
- 两类输入数据:
- 点数据(sample_Data):包含纬度(위도)、经度(경도)字段,示例数据:
索引 위도 경도 0 36.648365 127.486831 1 36.648365 127.486831 2 37.569615 126.819528 3 37.569615 126.819528 - 海岸线数据(gdf):GeoDataFrame格式,存储LINESTRING类型的海岸线线段,示例数据:
索引 geometry 0 LINESTRING (127.45000 34.45696, 127.44999 34.4...) 1 LINESTRING (127.49172 34.87526, 127.49173 34.8...) 2 LINESTRING (129.06340 37.61434, 129.06326 37.6...)
- 点数据(sample_Data):包含纬度(위도)、经度(경도)字段,示例数据:
现有实现与问题
当前使用的代码耗时约6小时,效率极低,代码如下:
def min_distance(x,y): sreach_point = Point(x,y) a = gdf.swifter.progress_bar(enable=True).apply(lambda x : geod.geometry_length(LineString(nearest_points(x['geometry'], sreach_point))),axis = 1) return a.min() sample_Data['거리']= sample_Data.apply(lambda x : min_distance(x['경도'],x['위도']),axis =1 ,result_type='expand')
疑问解答:交叉连接能否提升速度?
完全不能,反而会导致性能崩溃。交叉连接会生成点数据与海岸线线段的所有组合,数据量直接变为点数量 × 线段数量,计算量和内存占用会呈爆炸式增长,比当前的O(N*M)复杂度更糟糕。
高效优化方案
1. 利用空间索引筛选候选线段
GeoPandas的空间索引可以快速定位每个点附近的海岸线线段,避免遍历全部数据,是最有效的优化手段:
# 预先构建海岸线数据的空间索引 sindex = gdf.sindex def min_distance_optimized(lon, lat): point = Point(lon, lat) # 通过空间索引获取可能包含最近点的线段候选集 candidate_indices = list(sindex.intersection(point.bounds)) candidates = gdf.iloc[candidate_indices] # 仅在候选集中计算最近距离 distances = candidates.geometry.apply(lambda geom: geod.geometry_length(LineString(nearest_points(geom, point)))) return distances.min() # 应用优化后的函数 sample_Data['거리'] = sample_Data.apply(lambda row: min_distance_optimized(row['경도'], row['위도']), axis=1)
2. 使用GeoPandas内置的join_nearest批量处理
GeoPandas 0.10+版本支持sjoin_nearest,可以直接批量关联每个点的最近海岸线线段,再计算距离:
import geopandas as gpd # 将点数据转换为GeoDataFrame,确保与海岸线数据坐标系一致 points_gdf = gpd.GeoDataFrame( sample_Data, geometry=gpd.points_from_xy(sample_Data['경도'], sample_Data['위도']), crs=gdf.crs ) # 关联最近的海岸线线段 joined = gpd.sjoin_nearest(points_gdf, gdf, how='left') # 计算每个点到对应最近线段的距离 joined['거리'] = joined.apply( lambda row: geod.geometry_length(LineString(nearest_points(row['geometry_left'], row['geometry_right']))), axis=1 ) # 将结果合并回原数据框 sample_Data['거리'] = joined['거리']
3. 简化海岸线数据(可选)
如果海岸线数据包含大量精细微小线段,可以先对其进行简化,减少计算量:
# 简化海岸线线段,tolerance为简化阈值(单位与坐标系一致,如米) gdf_simplified = gdf.copy() gdf_simplified['geometry'] = gdf_simplified['geometry'].simplify(tolerance=10) # 之后使用简化后的gdf进行距离计算
注意调整tolerance值,平衡计算速度与距离精度。
内容的提问来源于stack exchange,提问作者정충호
相关产品推荐
相关产品推荐

