Python 查找从一个列表中的点到另一个列表中的点的最小距离之和?

Python 查找从一个列表中的点到另一个列表中的点的最小距离之和?,python,algorithm,optimization,linear-algebra,linear-programming,Python,Algorithm,Optimization,Linear Algebra,Linear Programming,我有两个分别包含x和y个n维点的列表。我必须计算列表一中每个点(包含x点)与第二个列表中每个点(包含y点)的最小距离之和。我计算的距离是欧几里德距离。需要优化的解决方案 我已经用Python实现了它的简单解决方案。但它的时间复杂性太大,无法在任何地方使用。将有可能进行优化。这个问题的时间复杂度能比我已经实现的要低吗 我正在读这篇文章,我正试图实现它。在这篇文章中,他们遇到了类似的问题,他们说这是一个特殊的条件。由于没有给出代码,因此无法知道它是如何实现的。因此,在我幼稚的实现中,上面的代码太慢,

我有两个分别包含x和y个n维点的列表。我必须计算列表一中每个点(包含x点)与第二个列表中每个点(包含y点)的最小距离之和。我计算的距离是欧几里德距离。需要优化的解决方案

我已经用Python实现了它的简单解决方案。但它的时间复杂性太大,无法在任何地方使用。将有可能进行优化。这个问题的时间复杂度能比我已经实现的要低吗

我正在读这篇文章,我正试图实现它。在这篇文章中,他们遇到了类似的问题,他们说这是一个特殊的条件。由于没有给出代码,因此无法知道它是如何实现的。因此,在我幼稚的实现中,上面的代码太慢,无法处理11k文档的数据集。我使用GoogleColab来执行我的代码

计算两点之间的欧氏距离 def欧几里得距离(x,y): dd=0.0 #len(x)是尺寸的数量。基本上x和y是一个 #包含点坐标的列表 对于范围内的i(len(x)): dd=dd+(x[i]-y[i])**2 返回日期**(1/2) #计算我们问题的期望解决方案 def区(l1、l2): 最小直径=0.0 dd=欧几里德距离(l1[0],l2[0]) 对于范围内的j(len(l1)): 对于范围内的k(len(l2)): 温度=欧几里德距离(l1[j],l2[k]) 如果dd>温度: dd=温度 min_dd=min_dd+dd dd=欧氏距离(l1[j],l2[0]) 返回最小值
要计算两点之间的距离,可以使用距离公式:

您可以在python中这样实现:

import math

def dist(x1, y1, x2, y2):
    return math.sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2))
然后,您所需要做的就是在X或Y列表上循环,检查两点的距离,如果它低于当前存储的最小距离,则将其存储。您应该最终得到一个O(n²)复杂度算法,这似乎是您想要的。下面是一个工作示例:

min_dd = None
for i in range(len(l1)):
    for j in range(i + 1, len(l1)):
        dd = dist(l1[i], l2[i], l1[j], l2[j])
        if min_dd is None or dd < min_dd:
            min_dd = dd
min\u dd=None
对于范围内的i(len(l1)):
对于范围(i+1,len(l1))内的j:
dd=距离(l1[i],l2[i],l1[j],l2[j])
如果min_dd为None或dd

使用此方法,即使点列表很大,也可以获得相当好的性能。

要计算两点之间的距离,可以使用距离公式:

您可以在python中这样实现:

import math

def dist(x1, y1, x2, y2):
    return math.sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2))
然后,您所需要做的就是在X或Y列表上循环,检查两点的距离,如果它低于当前存储的最小距离,则将其存储。您应该最终得到一个O(n²)复杂度算法,这似乎是您想要的。下面是一个工作示例:

min_dd = None
for i in range(len(l1)):
    for j in range(i + 1, len(l1)):
        dd = dist(l1[i], l2[i], l1[j], l2[j])
        if min_dd is None or dd < min_dd:
            min_dd = dd
min\u dd=None
对于范围内的i(len(l1)):
对于范围(i+1,len(l1))内的j:
dd=距离(l1[i],l2[i],l1[j],l2[j])
如果min_dd为None或dd

有了它,即使有大量的点列表,您也可以获得相当好的性能。

为了减少运行时间,我建议找到曼哈顿距离(δx+δy),对每个点的结果数组进行排序,然后创建一个曼哈顿最小距离+20%的缓冲区,如果排序列表中的值在+20%的范围内,您可以计算欧几里德距离并找到正确/最小欧几里德答案


这将减少一些时间,但20%的数字可能不会减少时间。如果这些点都很近,因为它们中的大多数将适合缓冲区,请尝试微调20%参数,以查看什么最适合您的数据集。请记住,由于欧几里德距离与曼哈顿距离的性质,过多地减少它可能会导致不准确的答案。

为了减少运行时间,我建议找到曼哈顿距离(δx+δy),对每个点的结果数组进行排序,然后创建一个曼哈顿最低距离+20%的缓冲区,如果排序列表中的值在+20%的范围内,则可以计算欧几里德距离并找到正确/最小欧几里德答案


这将减少一些时间,但20%的数字可能不会减少时间。如果这些点都很近,因为它们中的大多数将适合缓冲区,请尝试微调20%参数,以查看什么最适合您的数据集。请记住,由于欧几里德距离和曼哈顿距离的性质,过多地减少它可能会导致不准确的答案。

这类似于k-最近邻问题,因此找到离给定点最近的每个点的成本为O(N),而对于您的问题,成本应为O(N^2)


如果您的数据是低维的,有时使用可能会提高某些性能。

这类似于k-最近邻问题,因此找到与给定点最近的每个点的成本为O(N),而对于您的问题,成本应为O(N^2)

如果数据是低维的,有时使用可能会提高某些性能。

小数组 对于形状分别为
(n,)
(m,)
的两个numpy数组
x
y
,可以对距离计算进行矢量化,然后获得最小距离:

import numpy as np

n = 10
m = 20

x = np.random.random(n)
y = np.random.random(m)

# Using squared distance matrix and taking the
# square root at the minimum value
distance_matrix = (x[:,None]-y[None,:])**2
minimum_distance_sum = np.sum(np.sqrt(np.min(distance_matrix, axis=1)))
对于形状为
(n,l)
(m,l)
的数组,只需计算
距离矩阵

distance_matrix = np.sum((x[:,None]-y[None,:])**2, axis=2)
或者,您可以使用
np.linalg.norm
scipy.space.distance.cdist
np.einsum
等,但在许多情况下,它们的速度并不更快

大型阵列 如果上面的
l
n
m
太大,您无法将距离矩阵保存在内存中,您可以使用欧几里德距离的数学上下限来提高速度(请参阅。由于这依赖于for循环,因此速度会非常慢,但可以使用numba包装函数来解决这一问题:

import numpy as np
import numba

@numba.jit(nopython=True, fastmath=True)
def get_squared_distance(a,b):
    return np.sum((a-b)**2)

def get_minimum_distance_sum(x,y):
    n = x.shape[0]
    m = y.shape[0]
    l = x.shape[1]

    # Calculate mean and standard deviation of both arrays
    mx = np.mean(x, axis=1)
    my = np.mean(y, axis=1)
    sx = np.std(x, axis=1)
    sy = np.std(y, axis=1)
    return _get_minimum_distance_sum(x,y,n,m,l,mx,my,sx,sy)

@numba.jit(nopython=True, fastmath=True)
def _get_minimum_distance_sum(x,y,n,m,l,mx,my,sx,sy):
    min_distance_sum = 0
    for i in range(n):
        min_distance = get_squared_distance(x[i], y[0])
        for j in range(1,m):
            if i == 0 and j == 0:
                continue
            lower_bound = l * ((mx[i] - my[j])**2 + (sx[i] - sy[j])**2)
            if lower_bound >= min_distance:
                continue
            distance = get_squared_distance(x[i], y[j])
            if distance < min_distance:
                min_distance = distance
        min_distance_sum += np.sqrt(min_distance)

    return min_distance_sum

def test_minimum_distance_sum():
    # Will likely be much larger for this to be faster than the other method
    n = 10
    m = 20
    l = 100

    x = np.random.random((n,l))
    y = np.random.random((m,l))

    return get_minimum_distance_sum(x,y)
将numpy导入为np
进口麻木
@numba.jit(nopython=True,fastmath=True)
def获得平方距离(a,b):
返回np.和((a-b)**2)
def get_最小距离_总和(x,y):
n=x.shape[0]
m=y.形状[0]
l=x.形状[1]