【问题标题】:Find minimum distance between points of two lists in Python在Python中查找两个列表的点之间的最小距离
【发布时间】:2020-06-15 17:34:55
【问题描述】:

我有两个坐标列表:

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 的结构吗(例如使用二维数组而不是点)?

【问题讨论】:

  • 我不认为这比 O(n^2) aka 尝试所有其他方法更好。除非你做一些聪明的数学运算,让你以某种方式过滤s2 的每一项s1
  • 我想知道我是否可以利用 s1 实际上是一个坐标网格这一事实,并且确实没有必要尝试将 s2 的元素与 s1 的每个元素进行比较
  • s1 和 s2 在现实中会有多大?
  • @orak 这极大地改变了游戏规则。如果s2s1 的子集,那么其中会有一些等式(s1 的一些元素也会在s2 中所以最小距离将为0)。首先搜索这些将显着加快速度。 O((n-k)^2)k 共同元素的数量。
  • 可能感兴趣:erikbern.com/2018/02/15/…

标签: python optimization


【解决方案1】:

最简单的方法大概是使用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])

对于来自s1(也在s2 中的任何点)直接输出0 可能会获得更快的速度。

【讨论】:

    【解决方案2】:

    您是否尝试过使用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])
    

    您还可以通过将s1s2 替换为np.arrays 来提高性能,虽然scipy 可能在内部这样做,但我不确定。

    如果这还不够优化,我认为你可以在 O(ns2*log(ns2) + ns1 sub>) 通过查找s2 中的点的Voronoi diagram,然后循环遍历s1 以查看该点所在的区域将与s2 中的最近点匹配。

    【讨论】:

    • 妈的,比我快 7 秒 :D
    【解决方案3】:

    要计算 N 个距离,没有比暴力破解所有可能性更好的方法了。如果您想要更高级别的东西,例如最大或最小距离,您可以根据一些外部知识减少计算次数,但是给定您的设置,您将获得的最佳性能是 O(n^2) 性能.

    编辑:根据您的评论,有一些方法涉及一般的“分而治之”方法。 Wikipedia has a good overview,我将在这里复制一个可能相关的部分:

    使用递归分治法可以在 O(n log n) 时间内解决该问题,例如,如下:

    1. 根据 x 坐标对点进行排序。
    2. 用一条垂直线x = xmid将一组点分成两个大小相等的子集。
    3. 在左右子集中递归求解问题。这将分别产生左侧和右侧的最小距离 dLmindRmin。李>
    4. 在一组点对中找到最小距离dLRmin,其中一个点位于分界线的左侧,另一点位于右侧.
    5. 最终答案是dLmindRmindLRmin.

    【讨论】:

    • O(n log n) 算法不是只针对最近的一组点吗?您如何将其应用于在列表 (s2) 中找到与固定点最近的点的问题(以及对 s1 的所有点重复此操作)?
    【解决方案4】:

    蛮力确实是主要方式。由于您的数据是低维的,因此您可能可以使用 KDTree 获得一些性能。 scipy.spatial.KDTree

    kdtree = scipy.spatial.KDTree(s2)
    neighbours = kdtree.query(s1)
    

    【讨论】:

    【解决方案5】:

    您可以使用 sklearn pairwise_distances_argmin_min 的实现,给定两个点集 A 和 B 返回 B 中最近的点 pB 以及从 pA 到 pB 对于 A 中的每个点 pA

    然后在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
    

    在我测试过的所有实现中,这是最快的。它对点分布也没有任何限制(例如两个点集在空间上可以被平面分开等)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-16
      • 2022-08-14
      • 2021-10-24
      相关资源
      最近更新 更多