pandas中无需循环高效实现逐行跨行运算的方法
实现思路
你当前使用的逐行for循环效率低下,本质是没有利用numpy的向量化广播能力,且pandas逐行取数的索引开销会随数据量增长被放大。完全不需要写显式循环,通过数组维度扩展做批量计算,一次就能得到所有点对的haversine距离,运算速度可以提升2~3个数量级。
注意:你提供的原始代码存在参数顺序错误:haversine_np定义时第一个入参是经度lon1,但循环调用时第一个传入的是纬度值,会导致计算结果完全错误,下述实现已修正该问题。
向量化实现代码
import numpy as np import pandas as pd def batch_haversine(lon_arr, lat_arr): # 提前统一将角度转为弧度,避免重复计算 lon_rad = np.radians(lon_arr) lat_rad = np.radians(lat_arr) # 扩展数组维度,利用广播机制一次性生成所有点对的经纬度差 dlon = lon_rad[:, np.newaxis] - lon_rad[np.newaxis, :] dlat = lat_rad[:, np.newaxis] - lat_rad[np.newaxis, :] # 批量计算所有点对的haversine中间值 a = np.sin(dlat / 2.0)**2 + np.cos(lat_rad[:, np.newaxis]) * np.cos(lat_rad[np.newaxis, :]) * np.sin(dlon / 2.0)**2 c = 2 * np.arcsin(np.sqrt(a)) # 返回n*n的距离矩阵,单位为公里,matrix[i,j]对应第i个点到第j个点的距离 return 6367 * c # 加载你的示例数据 d1 = {'id': [1, 2, 3, 4, 5, 6, 7, 8, 9], 'longitude': [4.929783, 4.932333, 4.933950, 4.933900, 4.928467, 4.924583, 4.922133, 4.921400, 4.920967], 'latitude': [52.372250, 52.370884, 52.371101, 52.372234, 52.375282, 52.375950, 52.376301, 52.376232, 52.374481]} df = pd.DataFrame(data=d1) # 一次计算得到所有点对的距离,无Python层面的显式循环 distance_matrix = batch_haversine(df['longitude'].to_numpy(), df['latitude'].to_numpy()) # 如果需要和原表ID做映射,可以转为带索引的DataFrame distance_df = pd.DataFrame( distance_matrix, index=df['id'], columns=df['id'] )
超大数据量适配提示
如果你的数据集点数超过10万,全量n*n距离矩阵会占用极高内存(10万点对应1e10个矩阵元素,单精度浮点存储需要约40GB内存),这种场景不要强行计算全矩阵:
- 如果你的需求是查找每个点周边固定半径内的近邻,直接使用
scipy.spatial.cKDTree构建空间索引做球面近邻查询,内存占用和运算速度都远优于全量距离计算 - 如果必须输出全量点对距离,可以按行分块计算,每次仅计算部分行与全量点的距离,逐块写入存储避免内存溢出
内容的提问来源于stack exchange,提问作者Zubayer Islam
相关产品推荐
相关产品推荐

