您使用的半正矢方程中有很多次优的东西。您可以修剪其中的一部分,并最大限度地减少需要计算的正弦、余弦和平方根的数量。以下是我能想到的最好的,在我的系统上,在 1000 和 2000 个元素的两个随机数组上,它的运行速度比 Ophion 的代码(就矢量化而言基本相同)快 5 倍:
def spherical_dist(pos1, pos2, r=3958.75):
pos1 = pos1 * np.pi / 180
pos2 = pos2 * np.pi / 180
cos_lat1 = np.cos(pos1[..., 0])
cos_lat2 = np.cos(pos2[..., 0])
cos_lat_d = np.cos(pos1[..., 0] - pos2[..., 0])
cos_lon_d = np.cos(pos1[..., 1] - pos2[..., 1])
return r * np.arccos(cos_lat_d - cos_lat1 * cos_lat2 * (1 - cos_lon_d))
如果你“按原样”向它提供两个数组,它会抱怨,但这不是一个错误,而是一个功能。基本上,该函数计算球体在最后一个维度上的距离,并在其余维度上广播。所以你可以获得你想要的东西:
>>> spherical_dist(locations_1[:, None], locations_2)
array([[ 186.13522573, 345.46610882, 566.23466349, 282.51056676],
[ 187.96657622, 589.43369894, 555.55312473, 436.88855214],
[ 149.5853537 , 297.56950329, 440.81203371, 387.12153747]])
但它也可以用于计算两个点列表之间的距离,即:
>>> spherical_dist(locations_1, locations_2[:-1])
array([ 186.13522573, 589.43369894, 440.81203371])
或者在两个单点之间:
>>> spherical_dist(locations_1[0], locations_2[0])
186.1352257300577
这受到了 gufunc 工作方式的启发,一旦你习惯了它,我发现它是一种美妙的“瑞士军刀”编码风格,它可以让你在许多不同的设置中重用单个函数。