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