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

求助:优化Haversine距离矩阵计算,替代嵌套循环的高效实现方案

如何高效计算两组坐标间的Haversine距离矩阵(避免嵌套循环)

我现在用嵌套循环结合haversine库计算两组坐标的距离矩阵,虽然能跑,但处理大数据集时速度太慢。想找一种不用循环的高效替代方案,以下是当前代码:

import numpy as np
from haversine import haversine
    
string_list_1 = [(20.00,-100.1),...]  # 第一组坐标列表(纬度, 经度)
string_list_2 = [(21.00,-101.1),...]  # 第二组坐标列表

dist_mat = np.zeros((len(string_list_1), len(string_list_2)))

for i, coord1 in enumerate(string_list_1):
   dist_mat[i, :] = np.array([haversine(coord1, coord2) for coord2 in string_list_2])

求更高效、无循环的实现方式。


方案1:基于Numpy广播的全向量化实现(推荐)

核心思路是把坐标转换成Numpy数组,利用广播机制实现所有坐标对的批量计算,完全避开Python循环,底层用C执行计算,效率提升非常明显。

import numpy as np

def haversine_vectorize(lat1, lon1, lat2, lon2):
    # 转弧度
    lat1_rad = np.radians(lat1)
    lon1_rad = np.radians(lon1)
    lat2_rad = np.radians(lat2)
    lon2_rad = np.radians(lon2)
    
    # Haversine公式计算,通过维度扩展实现广播
    dlat = lat2_rad - lat1_rad[:, np.newaxis]
    dlon = lon2_rad - lon1_rad[:, np.newaxis]
    
    a = np.sin(dlat / 2)**2 + np.cos(lat1_rad[:, np.newaxis]) * np.cos(lat2_rad) * np.sin(dlon / 2)**2
    c = 2 * np.arcsin(np.sqrt(a))
    
    # 地球半径(单位:公里,若要英里替换为3956)
    r = 6371
    return c * r

# 转换坐标为Numpy数组
coords1 = np.array(string_list_1)
coords2 = np.array(string_list_2)

# 直接生成距离矩阵
dist_mat = haversine_vectorize(coords1[:, 0], coords1[:, 1], coords2[:, 0], coords2[:, 1])

解释:

  • 通过[:, np.newaxis]将第一组坐标的维度从(N,)扩展为(N,1),与第二组的(M,)维度运算时,Numpy会自动广播为(N,M)的矩阵,一次性完成所有坐标对的计算。
  • 全程无Python循环,所有运算在Numpy底层C代码执行,处理十万级坐标对也能快速完成。

方案2:用np.vectorize包装原haversine函数(快速改造)

如果不想自己实现Haversine公式,可以用np.vectorize把原标量函数包装成支持数组输入的函数,虽底层仍有循环,但比手动写Python循环更简洁高效:

import numpy as np
from haversine import haversine

# 包装成支持广播的向量化函数,指定输入输出签名
haversine_vec = np.vectorize(haversine, signature='(n),(n)->()')

coords1 = np.array(string_list_1)
coords2 = np.array(string_list_2)

# 调整维度实现广播计算
dist_mat = haversine_vec(coords1[:, np.newaxis, :], coords2[np.newaxis, :, :])

注意:此方案效率略逊于方案1,因为np.vectorize只是语法糖,但胜在无需修改原函数逻辑,快速完成改造。

方案3:利用scipy的cdist函数(备选)

若环境已安装scipy,可以用scipy.spatial.distance.cdist结合自定义距离函数,代码更简洁:

import numpy as np
from scipy.spatial.distance import cdist

def haversine_dist(coord1, coord2):
    lat1, lon1 = coord1
    lat2, lon2 = coord2
    # Haversine公式实现
    lat1_rad = np.radians(lat1)
    lon1_rad = np.radians(lon1)
    lat2_rad = np.radians(lat2)
    lon2_rad = np.radians(lon2)
    
    dlat = lat2_rad - lat1_rad
    dlon = lon2_rad - lon1_rad
    
    a = np.sin(dlat / 2)**2 + np.cos(lat1_rad) * np.cos(lat2_rad) * np.sin(dlon / 2)**2
    c = 2 * np.arcsin(np.sqrt(a))
    return 6371 * c

coords1 = np.array(string_list_1)
coords2 = np.array(string_list_2)

# 生成距离矩阵
dist_mat = cdist(coords1, coords2, metric=haversine_dist)

cdist内部会优化计算流程,效率高于手动循环,但仍略低于方案1的纯Numpy广播实现。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 07:53:42