You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

匹配两个Pandas DataFrame的GPS坐标新增列,双循环过慢有更优方案吗?

性能优化方案

核心问题分析

  • 原实现使用两层iterrows()遍历,单是iterrows()遍历效率就比向量化操作低1~2个数量级,叠加O(n*m)的时间复杂度(n是GPS点数量、m是待匹配地点数量),数据量稍大就会出现明显卡顿。

方案1:KD树最近邻搜索(最优推荐,时间复杂度O(n*logm))

利用KD树做空间索引批量查询最近邻,是大规模数据下的最优选择,性能提升可达上千倍:

新增依赖

import numpy as np
from scipy.spatial import KDTree

实现代码

# 1. 预处理坐标,转为弧度制(适配Haversine球面距离计算)
# 提取待匹配地点的坐标数组(纬度、经度顺序,转弧度)
loc_arr = np.radians([[p.x, p.y] for p in df_locations['gps']])
# 构建KD树,使用Haversine球面距离
tree = KDTree(loc_arr, metric='haversine')
# 提取GPS点的坐标数组,转弧度
gps_arr = np.radians([[p.x, p.y] for p in df_gps['points']])

# 2. 批量查询最近邻,k=1表示只取最近的1个点
distances, indices = tree.query(gps_arr, k=1)

# 3. 匹配地点名称,距离转英里(地球半径约3956英里)
df_gps['closest_city'] = df_locations['location'].iloc[indices].values
df_gps['distance_miles'] = distances * 3956

方案2:向量化广播计算(适合中小规模数据)

如果两个表的数据量都不大(总组合数不超过100万),可以用广播实现全量距离计算,无需额外依赖:

# 1. 拆分坐标为单独列
df_gps[['lat', 'lon']] = df_gps['points'].apply(lambda p: pd.Series([p.x, p.y]))
df_locations[['loc_lat', 'loc_lon']] = df_locations['gps'].apply(lambda p: pd.Series([p.x, p.y]))

# 2. 向量化计算所有GPS点到所有地点的距离(Haversine公式向量化实现)
lat1, lon1 = np.radians(df_gps['lat'].values), np.radians(df_gps['lon'].values)
lat2, lon2 = np.radians(df_locations['loc_lat'].values), np.radians(df_locations['loc_lon'].values)

# 广播扩展维度计算差值
dlat = lat2[np.newaxis, :] - lat1[:, np.newaxis]
dlon = lon2[np.newaxis, :] - lon1[:, np.newaxis]
a = np.sin(dlat / 2)**2 + np.cos(lat1[:, np.newaxis]) * np.cos(lat2[np.newaxis, :]) * np.sin(dlon / 2)**2
c = 2 * np.arcsin(np.sqrt(a))
distance_matrix = c * 3956 # 转换为英里单位

# 3. 取距离最小的对应地点
min_indices = distance_matrix.argmin(axis=1)
df_gps['closest_city'] = df_locations['location'].iloc[min_indices].values

性能对比

以1万条GPS点、1千个待匹配地点为例:

  • 原双循环实现:约需30秒以上
  • 向量化广播实现:约需0.1秒
  • KD树实现:约需0.01秒

内容的提问来源于stack exchange,提问作者kdbaseball8

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 21:36:03