Python 成对haversine距离计算
我有两个数组,分别是lat和long。我想计算阵列中每对lat和long以及每对lat和long之间的距离。 这是我的两个数组Python 成对haversine距离计算,python,arrays,performance,numpy,haversine,Python,Arrays,Performance,Numpy,Haversine,我有两个数组,分别是lat和long。我想计算阵列中每对lat和long以及每对lat和long之间的距离。 这是我的两个数组 lat_array array([ 0.33356456, 0.33355585, 0.33355585, 0.33401788, 0.33370132, 0.33370132, 0.33370132, 0.33371075, 0.33371075, 0.33370132, 0.33370132, 0.33370132
lat_array
array([ 0.33356456, 0.33355585, 0.33355585, 0.33401788, 0.33370132,
0.33370132, 0.33370132, 0.33371075, 0.33371075, 0.33370132,
0.33370132, 0.33370132, 0.33356488, 0.33356488, 0.33370132,
0.33370132, 0.33370132, 0.33401788, 0.33362632, 0.33362632,
0.33364007, 0.33370132, 0.33401788, 0.33401788, 0.33358399,
0.33358399, 0.33358399, 0.33370132, 0.33370132, 0.33362632,
0.33370132, 0.33370132, 0.33370132, 0.33370132, 0.33370132,
0.33356488, 0.33356456, 0.33391071, 0.33370132, 0.33356488,
0.33356488, 0.33356456, 0.33356456, 0.33356456, 0.33362632,
0.33364804, 0.3336314 , 0.33370132, 0.33370132, 0.33370132,
0.33364034, 0.33359921, 0.33370132, 0.33360397, 0.33348863,
0.33370132])
long_array
array([ 1.27253229, 1.27249141, 1.27249141, 1.27259085, 1.2724337 ,
1.2724337 , 1.2724337 , 1.27246931, 1.27246931, 1.2724337 ,
1.2724337 , 1.2724337 , 1.27254305, 1.27254305, 1.2724337 ,
1.2724337 , 1.2724337 , 1.27259085, 1.27250461, 1.27250461,
1.27251211, 1.2724337 , 1.27259085, 1.27259085, 1.27252134,
1.27252134, 1.27252134, 1.2724337 , 1.2724337 , 1.27250461,
1.2724337 , 1.2724337 , 1.2724337 , 1.2724337 , 1.2724337 ,
1.27254305, 1.27253229, 1.27266808, 1.2724337 , 1.27254305,
1.27254305, 1.27253229, 1.27253229, 1.27253229, 1.27250461,
1.27250534, 1.27250184, 1.2724337 , 1.2724337 , 1.2724337 ,
1.27251339, 1.27223739, 1.2724337 , 1.2722575 , 1.27237575,
1.2724337 ])
转换成弧度后。现在我想知道第一对lat和long之间的距离,以及剩余对lat和long之间的距离,依此类推。并要打印出对和相应的距离
这就是我在python中所做的
distance = []
R = 6371.0
for i in range(len(lat_array)):
for j in (i+1,len(lat_array)):
dlon = long_array[j]-long_array[i]
dlat = lat_array[j]-lat_array[i]
a = sin(dlat / 2)**2 + cos(lat_array[i]) * cos(lat_array[j]) *
sin(dlon / 2)**2
c = 2 * atan2(sqrt(a), sqrt(1 - a))
distance.append(R * c)
它给了我一个错误索引器错误:索引56超出了大小为56的轴0的界限
我哪里做错了?如果阵列很大,如何加快计算速度?请帮助。您的代码输入错误。改变
for j in (i+1,len(lat_array)):
到
否则,您将迭代由两个元素组成的元组i+1
和len(lat\u数组)
。第二个导致错误。假设lat
和lng
作为晶格和经度数组,并且这些数组的数据以弧度为单位,这里有一个基于-
现在,上述方法将为我们提供所有对的输出,而不管它们的顺序如何。因此,对于这两对,我们将有两个距离输出:(点1,点2)
&(点2,点1)
,即使距离是相同的。因此,为了节省内存并希望获得更好的性能,您可以创建唯一的成对ID,并修改前面列出的方法,如下所示-
# Elementwise differentiations for lattitudes & longitudes,
# but not repeat for the same paired elements
N = lat.size
idx1,idx2 = np.triu_indices(N,1)
dflat = lat[idx2] - lat[idx1]
dflng = lng[idx2] - lng[idx1]
# Finally Calculate haversine using its distance formula
d = np.sin(dflat/2)**2 + np.cos(lat[idx2])*np.cos(lat[idx1]) * np.sin(dflng/2)**2
hav_dists = 2 * 6371 * np.arcsin(np.sqrt(d))
函数定义-
def original_app(lat,lng):
distance = []
R = 6371.0
for i in range(len(lat)):
for j in range(i+1,len(lat)):
dlon = lng[j]-lng[i]
dlat = lat[j]-lat[i]
a = sin(dlat / 2)**2 + cos(lat[i]) * cos(lat[j]) * sin(dlon / 2)**2
c = 2 * atan2(sqrt(a), sqrt(1 - a))
distance.append(R * c)
return distance
def vectorized_app1(lat,lng):
dflat = lat[:,None] - lat
dflng = lng[:,None] - lng
d = np.sin(dflat/2)**2 + np.cos(lat[:,None])*np.cos(lat) * np.sin(dflng/2)**2
return 2 * 6371 * np.arcsin(np.sqrt(d))
def vectorized_app2(lat,lng):
N = lat.size
idx1,idx2 = np.triu_indices(N,1)
dflat = lat[idx2] - lat[idx1]
dflng = lng[idx2] - lng[idx1]
d =np.sin(dflat/2)**2+np.cos(lat[idx2])*np.cos(lat[idx1])*np.sin(dflng/2)**2
return 2 * 6371 * np.arcsin(np.sqrt(d))
验证输出-
In [78]: lat
Out[78]: array([ 0.33356456, 0.33355585, 0.33355585, 0.33401788, 0.33370132])
In [79]: lng
Out[79]: array([ 1.27253229, 1.27249141, 1.27249141, 1.27259085, 1.2724337 ])
In [80]: original_app(lat,lng)
Out[80]:
[0.2522702110418014,
0.2522702110418014,
2.909533226553249,
1.0542204712876762,
0.0,
3.003834632906676,
0.9897592295963831,
3.003834632906676,
0.9897592295963831,
2.2276138997714474]
In [81]: vectorized_app1(lat,lng)
Out[81]:
array([[ 0. , 0.25227021, 0.25227021, 2.90953323, 1.05422047],
[ 0.25227021, 0. , 0. , 3.00383463, 0.98975923],
[ 0.25227021, 0. , 0. , 3.00383463, 0.98975923],
[ 2.90953323, 3.00383463, 3.00383463, 0. , 2.2276139 ],
[ 1.05422047, 0.98975923, 0.98975923, 2.2276139 , 0. ]])
In [82]: vectorized_app2(lat,lng)
Out[82]:
array([ 0.25227021, 0.25227021, 2.90953323, 1.05422047, 0. ,
3.00383463, 0.98975923, 3.00383463, 0.98975923, 2.2276139 ])
运行时测试-
In [83]: lat = np.random.randn(1000)
In [84]: lng = np.random.randn(1000)
In [85]: %timeit original_app(lat,lng)
1 loops, best of 3: 2.11 s per loop
In [86]: %timeit vectorized_app1(lat,lng)
1 loops, best of 3: 263 ms per loop
In [87]: %timeit vectorized_app2(lat,lng)
1 loops, best of 3: 224 ms per loop
因此,就性能而言,向量化app2似乎是一条可行之路 由于这是目前谷歌“两两哈弗斯线距离”的最高结果,我再加上两分:如果你能访问scikit learn
,这个问题可以很快解决。查看时,您会注意到不支持“haversine”度量,但它是在中实现的
这意味着您可以执行以下操作:
from sklearn.neighbors import DistanceMetric
def sklearn_haversine(lat, lon):
haversine = DistanceMetric.get_metric('haversine')
latlon = np.hstack((lat[:, np.newaxis], lon[:, np.newaxis]))
dists = haversine.pairwise(latlon)
return 6371 * dists
请注意,lat
和lon
的串联仅是必要的,因为它们是独立的数组。如果您将它们作为shape(n_samples,2)
的组合数组传递,您可以直接对它们调用haversine.pairwise
。此外,仅当需要以公里为单位的距离时,才需要乘以6371
。例如,如果您只想找到最近的一对点,则无需执行此步骤
核查:
In [87]: lat = np.array([ 0.33356456, 0.33355585, 0.33355585, 0.33401788, 0.33370132])
In [88]: lng = np.array([ 1.27253229, 1.27249141, 1.27249141, 1.27259085, 1.2724337 ])
In [89]: sklearn_haversine(lat, lng)
Out[89]:
array([[ 0. , 0.25227021, 0.25227021, 2.90953323, 1.05422047],
[ 0.25227021, 0. , 0. , 3.00383463, 0.98975923],
[ 0.25227021, 0. , 0. , 3.00383463, 0.98975923],
[ 2.90953323, 3.00383463, 3.00383463, 0. , 2.2276139 ],
[ 1.05422047, 0.98975923, 0.98975923, 2.2276139 , 0. ]])
性能:
In [91]: lat = np.random.randn(1000)
In [92]: lng = np.random.randn(1000)
In [93]: %timeit original_app(lat,lng)
1 loops, best of 3: 1.46 s per loop
In [94]: %timeit vectorized_app1(lat,lng)
10 loops, best of 3: 86.7 ms per loop
In [95]: %timeit vectorized_app2(lat,lng)
10 loops, best of 3: 75.7 ms per loop
In [96]: %timeit sklearn_haversine(lat,lng)
10 loops, best of 3: 76 ms per loop
总之,您可以以更短、更简单的代码获得Divakar的矢量化_app1
的输出,速度为矢量化_app2
。可以使用scikit learn 0.21.0(2019-05年发布)中引入的haversine_distances函数。示例命令:
% ipython
Python 3.8.5 (default, Sep 4 2020, 07:30:14)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.18.1 -- An enhanced Interactive Python. Type '?' for help.
In [1]:
import numpy as np
lat = np.array([ 0.33356456, 0.33355585, 0.33355585, 0.33401788, 0.33370132])
lon = np.array([ 1.27253229, 1.27249141, 1.27249141, 1.27259085, 1.2724337 ])
position = np.column_stack((lat, lon))
position
Out[1]:
array([[0.33356456, 1.27253229],
[0.33355585, 1.27249141],
[0.33355585, 1.27249141],
[0.33401788, 1.27259085],
[0.33370132, 1.2724337 ]])
In [2]:
from sklearn.metrics.pairwise import haversine_distances
R = 6371.0
D1 = R * haversine_distances(position)
D1
Out[2]:
array([[0. , 0.25227021, 0.25227021, 2.90953323, 1.05422047],
[0.25227021, 0. , 0. , 3.00383463, 0.98975923],
[0.25227021, 0. , 0. , 3.00383463, 0.98975923],
[2.90953323, 3.00383463, 3.00383463, 0. , 2.2276139 ],
[1.05422047, 0.98975923, 0.98975923, 2.2276139 , 0. ]])
参考:-
- -变更日志
入口
- -
显示发布日期
哦,我明白了。。那真是个愚蠢的错误。但是我如何用距离打印这些对呢?lat[:,None]
是什么意思?@kfx这意味着我们通过添加一个单元素维度(维度上的元素数量为1)将lat从一维数组扩展到二维数组,这样当减去lat
时,广播将发生,我们将把lat
中的每个元素与其中的所有其他元素相减,作为一个2D数组。有关更多信息,请参阅有关广播的文档-
In [91]: lat = np.random.randn(1000)
In [92]: lng = np.random.randn(1000)
In [93]: %timeit original_app(lat,lng)
1 loops, best of 3: 1.46 s per loop
In [94]: %timeit vectorized_app1(lat,lng)
10 loops, best of 3: 86.7 ms per loop
In [95]: %timeit vectorized_app2(lat,lng)
10 loops, best of 3: 75.7 ms per loop
In [96]: %timeit sklearn_haversine(lat,lng)
10 loops, best of 3: 76 ms per loop
% ipython
Python 3.8.5 (default, Sep 4 2020, 07:30:14)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.18.1 -- An enhanced Interactive Python. Type '?' for help.
In [1]:
import numpy as np
lat = np.array([ 0.33356456, 0.33355585, 0.33355585, 0.33401788, 0.33370132])
lon = np.array([ 1.27253229, 1.27249141, 1.27249141, 1.27259085, 1.2724337 ])
position = np.column_stack((lat, lon))
position
Out[1]:
array([[0.33356456, 1.27253229],
[0.33355585, 1.27249141],
[0.33355585, 1.27249141],
[0.33401788, 1.27259085],
[0.33370132, 1.2724337 ]])
In [2]:
from sklearn.metrics.pairwise import haversine_distances
R = 6371.0
D1 = R * haversine_distances(position)
D1
Out[2]:
array([[0. , 0.25227021, 0.25227021, 2.90953323, 1.05422047],
[0.25227021, 0. , 0. , 3.00383463, 0.98975923],
[0.25227021, 0. , 0. , 3.00383463, 0.98975923],
[2.90953323, 3.00383463, 3.00383463, 0. , 2.2276139 ],
[1.05422047, 0.98975923, 0.98975923, 2.2276139 , 0. ]])