我有两个坐标列表:
s1 = [(0,0), (0,1), (1,0), (1,1)]
s2 = [(3,2), (1,9)]
我想计算s1中每个点到s2中任意点的最小距离。例如结果应如下。
result = [3.60, 3.16, 2.82, 2.23]
问题:为了达到这个效果,在执行时间方面最优化的方法是什么?
到目前为止,我已经尝试了这个,但执行时间并不乐观:
import math
def nearestDistance(boundary, p):
minDistList = map(lambda b: (b[0] - p[0])**2 + (b[1] - p[1])**2, boundary)
minDist2 = min(minDistList)
return math.sqrt(float(minDist2))
d = []
for p in s1:
d.append(nearestDistance(s2, p))
我应该更改s1和s2的结构(而不是点使用2d数组)吗?
答案 0 :(得分:5)
最简单的方法可能是使用scipy.spatial.distance.cdist
:
import numpy as np
from scipy.spatial import distance
s1 = np.array([(0,0), (0,1), (1,0), (1,1)])
s2 = np.array([(3,2), (1,9)])
print(distance.cdist(s1,s2).min(axis=1))
# array([3.60555128, 3.16227766, 2.82842712, 2.23606798])
直接输出来自0
s1
的{{1}}的任何点的s2
可能会获得更快的速度。
答案 1 :(得分:4)
您是否尝试过使用cdist
:
import numpy as np
from scipy.spatial.distance import cdist
np.min(cdist(s1,s2))
返回
array([ 3.60555128, 3.16227766, 2.82842712, 2.23606798])
您可以通过将s1
和s2
替换为np.array
来获得性能提升,尽管scipy
可能在内部执行此操作,但我不确定。< / p>
如果这还不够优化,我想你可以在O(n s2 * log(n s2 )+ n s1 )找到s2
中点的Voronoi diagram,然后循环s1
,看看点落在哪个区域与s2
中的最近点匹配
答案 2 :(得分:2)
要计算N个距离,这不是一个比暴力强迫所有可能性更好的方法。如果你想要更高级别的东西,比如可能是最大或最小的距离,你可以根据一些外部知识减少计算次数,但是给定你的设置,你得到的最好的是O(n ^ 2) )表现。
编辑:鉴于你的评论,有一些方法,涉及一般&#34;分裂和征服&#34;做法。 Wikipedia has a good overview,我将在这里复制一个可能相关的内容:使用递归分治法可以在O( n log n )时间内解决问题,例如:
- 根据x坐标对点进行排序。
- 通过垂直线 x = x mid 将这组点分成两个大小相等的子集。
- 在左右子集中递归地解决问题。这分别产生左侧和右侧最小距离 d Lmin 和 d Rmin 。
- 在一组点对中找到最小距离 d LRmin ,其中一个点位于分隔垂直的左侧,另一个点位于右侧
- 最终答案是 d Lmin , d Rmin 和 d <之间的最小答案子> LRmin 子> 的
醇>
答案 3 :(得分:2)
蛮力真的是主要方式。由于您的数据维度较低,因此您可以使用KDTree来获得一些性能。 scipy.spatial.KDTree
kdtree = scipy.spatial.KDTree(s2)
neighbours = kdtree.query(s1)
答案 4 :(得分:1)
您可以使用sklearn pairwise_distances_argmin_min的实现,给定两个点集A和B返回B中最接近的点 p B和距 pA 的距离A中每个点 pA 的 pB 。
然后在O(n * log n)中选择所有距离最小的点对:
from sklearn.metrics import pairwise_distances_argmin_min
import numpy as np
def get_closest_pair_of_points(point_list_1: List[Tuple[float]],
point_list_2: List[Tuple[float]]) -> Tuple[Tuple, Tuple, float]:
"""
Determine the two points from two disjoint lists of points that are closest to
each other and the distance between them.
Args:
point_list_1: First list of points.
point_list_2: Second list of points.
Returns:
Two points that make the closest distance and the distance between them.
"""
indeces_of_closest_point_in_list_2, distances = pairwise_distances_argmin_min(point_list_1, point_list_2)
# Get index of a point pair that makes the smallest distance.
min_distance_pair_index = np.argmin(distances)
# Get the two points that make this smallest distance.
min_distance_pair_point_1 = point_list_1[min_distance_pair_index]
min_distance_pair_point_2 = point_list_2[indeces_of_closest_point_in_list_2[min_distance_pair_index]]
min_distance = distances[min_distance_pair_index]
return min_distance_pair_point_1, min_distance_pair_point_2, min_distance
在我测试过的所有实现中,这是最快的。它对点的分布也没有任何限制(例如,两个点集在空间上可以通过平面分离等)