Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/297.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 两个不同Numpy数组中点之间的最小欧氏距离,不在_Python_Numpy_Euclidean Distance - Fatal编程技术网

Python 两个不同Numpy数组中点之间的最小欧氏距离,不在

Python 两个不同Numpy数组中点之间的最小欧氏距离,不在,python,numpy,euclidean-distance,Python,Numpy,Euclidean Distance,我有两个x-y坐标的数组,我想找到一个数组中每个点与另一个数组中所有点之间的最小欧几里德距离。数组的大小不一定相同。例如: xy1=numpy.array( [[ 243, 3173], [ 525, 2997]]) xy2=numpy.array( [[ 682, 2644], [ 277, 2651], [ 396, 2640]]) 我当前的方法在xy1中循环遍历每个坐标xy,并计算该坐标与其他坐标之间的距离 mindist=numpy.zeros(len(xy1)) minid

我有两个x-y坐标的数组,我想找到一个数组中每个点与另一个数组中所有点之间的最小欧几里德距离。数组的大小不一定相同。例如:

xy1=numpy.array(
[[  243,  3173],
[  525,  2997]])

xy2=numpy.array(
[[ 682, 2644],
[ 277, 2651],
[ 396, 2640]])
我当前的方法在
xy1
中循环遍历每个坐标
xy
,并计算该坐标与其他坐标之间的距离

mindist=numpy.zeros(len(xy1))
minid=numpy.zeros(len(xy1))

for i,xy in enumerate(xy1):
    dists=numpy.sqrt(numpy.sum((xy-xy2)**2,axis=1))
    mindist[i],minid[i]=dists.min(),dists.argmin()
有没有办法消除for循环,并在两个数组之间进行逐元素计算?我设想生成一个距离矩阵,我可以在每行或每列中找到最小元素


另一种看待问题的方式。假设我将
xy1
(长度m)和
xy2
(长度p)连接到
xy
(长度n),然后存储原始数组的长度。理论上,我应该能够从这些坐标中生成一个nxn距离矩阵,从中我可以得到一个mxp子矩阵。有没有一种方法可以有效地生成此子矩阵?

用于您尝试执行的操作:

dists = numpy.sqrt((xy1[:, 0, numpy.newaxis] - xy2[:, 0])**2 + (xy1[:, 1, numpy.newaxis - xy2[:, 1])**2)
mindist = numpy.min(dists, axis=1)
minid = numpy.argmin(dists, axis=1)
编辑:您可以使用
numpy.hypot
,而不是调用
sqrt
,执行正方形等操作:

dists = numpy.hypot(xy1[:, 0, numpy.newaxis]-xy2[:, 0], xy1[:, 1, numpy.newaxis]-xy2[:, 1])

要计算距离的m×p矩阵,这应该是可行的:

>>> def distances(xy1, xy2):
...   d0 = numpy.subtract.outer(xy1[:,0], xy2[:,0])
...   d1 = numpy.subtract.outer(xy1[:,1], xy2[:,1])
...   return numpy.hypot(d0, d1)
.outer
调用生成两个这样的矩阵(沿两个轴的标量差),
.hypot
调用将这些矩阵转换为相同的形状矩阵(标量欧氏距离)。

(几个月后)
scipy.space.distance.cdist(X,Y)
给出所有的距离对, 对于X和Y 2尺寸、3尺寸…
它也有22种不同的规范,详细说明


被接受的答案没有完全解决问题,该问题要求找到两组点之间的最小距离,而不是两组点中每个点之间的距离

尽管原始问题的简单解决方案实际上包括计算每对之间的距离并随后找到最小距离,但如果只对最小距离感兴趣,则无需这样做。后一个问题有一个更快的解决方案

所有建议的解决方案都有一个运行时间,其规模为
m*p=len(xy1)*len(xy2)
。这对于小型数据集来说是可以的,但是可以编写一个最佳的解决方案,它可以扩展为
m*log(p)
,为大型
xy2
数据集带来巨大的节省

这种最佳执行时间缩放可以通过以下方式实现

import numpy as np
from scipy import spatial

xy1 = np.array(
    [[243,  3173],
     [525,  2997]])

xy2 = np.array(
    [[682, 2644],
     [277, 2651],
     [396, 2640]])

# This solution is optimal when xy2 is very large
tree = spatial.cKDTree(xy2)
mindist, minid = tree.query(xy1)
print(mindist)

# This solution by @denis is OK for small xy2
mindist = np.min(spatial.distance.cdist(xy1, xy2), axis=1)
print(mindist)

其中,
mindist
xy1
中的每个点与
xy2

中的一组点之间的最小距离,我认为以下功能也起作用

import numpy as np
from typing import Optional
def pairwise_dist(X: np.ndarray, Y: Optional[np.ndarray] = None) -> np.ndarray:
    Y = X if Y is None else Y
    xx = (X ** 2).sum(axis = 1)[:, None]
    yy = (Y ** 2).sum(axis = 1)[:, None]
    return xx + yy.T - 2 * (X @ Y.T)
解释
假设
X
Y
的每一行都是两组点的坐标。
让它们的大小分别为
mxp
pxn


结果将生成一个大小为
mxn
的numpy数组,其中
(i,j)
-th条目分别是
i
-th行与
X
Y
j
-th行之间的距离。

噢,天哪,这太神奇了。我没有意识到一个元素一个元素也可以这样工作。因此
xy1[:,0,numpy.newaxis]
作为列向量有效地替换了我的for循环,从中减去
xy2
的所有x值。很酷,谢谢。是的。有关更一般和更优雅的方法,请参见Alex的答案。@fideli:help(numpy.subtract.outer)告诉您,Alok的numpy.newaxis技巧也在Alex的答案中起作用。如果您需要加快代码的速度,您应该删除不必要的numpy.sqrt(并且只有在找到最小平方距离的平方根时才使用)@denis cdist计算所有对之间的距离。假设
X
Y
具有相同的长度
N
,例如,
[dist(X[0],Y[0]),dist(X[1],Y[1]),…dist(X[N],Y[N]),
之间的距离如何只存在于相应的元素之间呢?@LWZ,就是你所拥有的--
np数组([dist(X,Y)表示zip(X,Y)]
,这是有效的!而且很快。请注意,要计算的元素的长度必须为2,否则python将引发错误。对于opencv2检测到的轮廓中的点列表,我需要先使用numpy的整形函数对其进行整形…@denis:例如,cv2.findContours的结果是这样的:[[[x1 y1]][[x2 y2]]…[[xn yn]]。我不知道他们为什么把坐标放在2个方括号里,但是如果你直接把cdist应用到列表中,每个元素只有长度1(一个列表,里面有一个列表),我必须重新塑造它,使轮廓成为长度2元素的列表(这意味着平放双括号)@Jim Raynor,右——cdist期望ndim==2的数组,如果选中,在这种情况下我会选择cdist,但是+1'd,我从这个解决方案中学到了很多stuff@Alex:有没有一种有效的方法可以将其推广到两列以上?@Mac,请参阅公认的答案和
scipy.space.distance.cdist
@Alex:谢谢,我确实看到了。不过,我更希望有一种方法可以特别概括您的代码,这样我就不必为这一个函数添加对SciPy的依赖。无论如何,谢谢。@Mac,我不知道我是否理解你的问题,但是为什么不做np.hypot(np.hypot(d0,d1),d2)等等(这里d2硬编码,只是为了一个例子)来获得更多的维度?这非常有效!这是唯一可以推广到任意维数的解决方案。
import numpy as np
from scipy import spatial

xy1 = np.array(
    [[243,  3173],
     [525,  2997]])

xy2 = np.array(
    [[682, 2644],
     [277, 2651],
     [396, 2640]])

# This solution is optimal when xy2 is very large
tree = spatial.cKDTree(xy2)
mindist, minid = tree.query(xy1)
print(mindist)

# This solution by @denis is OK for small xy2
mindist = np.min(spatial.distance.cdist(xy1, xy2), axis=1)
print(mindist)
import numpy as np
from typing import Optional
def pairwise_dist(X: np.ndarray, Y: Optional[np.ndarray] = None) -> np.ndarray:
    Y = X if Y is None else Y
    xx = (X ** 2).sum(axis = 1)[:, None]
    yy = (Y ** 2).sum(axis = 1)[:, None]
    return xx + yy.T - 2 * (X @ Y.T)