我有一个数据集如下,
Id Latitude longitude
1 25.42 55.47
2 25.39 55.47
3 24.48 54.38
4 24.51 54.54
我想为数据集的每个点找到最近的距离。我在互联网上找到了以下距离函数,
from math import radians, cos, sin, asin, sqrt
def distance(lon1, lat1, lon2, lat2):
"""
Calculate the great circle distance between two points
on the earth (specified in decimal degrees)
"""
# convert decimal degrees to radians
lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
# haversine formula
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * asin(sqrt(a))
km = 6367 * c
return km
我正在使用以下功能,
shortest_distance = []
for i in range(1,len(data)):
distance1 = []
for j in range(1,len(data)):
distance1.append(distance(data['Longitude'][i], data['Latitude'][i], data['Longitude'][j], data['Latitude'][j]))
shortest_distance.append(min(distance1))
但是此代码为每个条目循环两次并返回 n^2 次迭代,因此它非常慢。我的数据集包含近 100 万条记录,每次遍历所有元素两次变得非常昂贵。
我想找到更好的方法来找出每一行的最近点。谁能帮我找到在 python 中解决这个问题的方法?
谢谢
原文由 haimen 发布,翻译遵循 CC BY-SA 4.0 许可协议
找到最近的
N
指向给定点的蛮力方法是O(N)
你必须检查每个点。相反,如果N
点存储在 KD 树 中,则找到最近的点平均为O(log(N))
。还有构建 KD 树的额外一次性成本,这需要O(N)
时间。如果需要重复这个过程
N
次,那么暴力法是O(N**2)
,kd-tree法是O(N*log(N))
因此,对于足够大的N
,KD 树将击败蛮力方法。有关最近邻算法(包括 KD 树)的更多信息,请参见 此处。
下面(在函数
using_kdtree
中)是一种使用scipy.spatial.kdtree
计算最近邻的大圆弧长的方法。scipy.spatial.kdtree
使用点之间的欧氏距离,但是有一个 公式 可以将球体上点之间的欧氏弦距离转换为大圆弧长(给定球体的半径)。所以想法是将纬度/经度数据转换为笛卡尔坐标,使用KDTree
找到最近的邻居,然后应用 大圆距离公式 以获得所需的结果。这里有一些基准。使用
N = 100
,using_kdtree
比orig
(蛮力)方法快 39 倍。对于
N = 10000
:Since
using_kdtree
isO(N log(N))
andorig
isO(N**2)
, the factor by whichusing_kdtree
is faster thanorig
将增长为N
,data
的长度增长。