两个不同Numpy阵列中点之间的最小欧几里德距离,而不是在

时间:2009-12-09 04:11:17

标签: python numpy euclidean-distance

我有两个 x - y 坐标数组,我想在一个数组中找到每个点之间的最小欧几里德距离使用 all 其他数组中的点。阵列的大小不一定相同。例如:

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

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

我当前的方法遍历xy中的每个坐标xy1,并计算该坐标与其他坐标之间的距离。

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 ),我存储原始数组的长度。从理论上讲,我应该能够从那些坐标中生成 n x n 距离矩阵,我可以从中获取 m x p 子矩阵。有没有办法有效地生成这个子矩阵?

6 个答案:

答案 0 :(得分:39)

(几个月后) scipy.spatial.distance.cdist( X, Y ) 给出所有距离, 对于X和Y 2暗淡,3暗淡...
它还有22种不同的规范,详细说明 here

# cdist example: (nx,dim) (ny,dim) -> (nx,ny)

from __future__ import division
import sys
import numpy as np
from scipy.spatial.distance import cdist

#...............................................................................
dim = 10
nx = 1000
ny = 100
metric = "euclidean"
seed = 1

    # change these params in sh or ipython: run this.py dim=3 ...
for arg in sys.argv[1:]:
    exec( arg )
np.random.seed(seed)
np.set_printoptions( 2, threshold=100, edgeitems=10, suppress=True )

title = "%s  dim %d  nx %d  ny %d  metric %s" % (
        __file__, dim, nx, ny, metric )
print "\n", title

#...............................................................................
X = np.random.uniform( 0, 1, size=(nx,dim) )
Y = np.random.uniform( 0, 1, size=(ny,dim) )
dist = cdist( X, Y, metric=metric )  # -> (nx, ny) distances
#...............................................................................

print "scipy.spatial.distance.cdist: X %s Y %s -> %s" % (
        X.shape, Y.shape, dist.shape )
print "dist average %.3g +- %.2g" % (dist.mean(), dist.std())
print "check: dist[0,3] %.3g == cdist( [X[0]], [Y[3]] ) %.3g" % (
        dist[0,3], cdist( [X[0]], [Y[3]] ))


# (trivia: how do pairwise distances between uniform-random points in the unit cube
# depend on the metric ? With the right scaling, not much at all:
# L1 / dim      ~ .33 +- .2/sqrt dim
# L2 / sqrt dim ~ .4 +- .2/sqrt dim
# Lmax / 2      ~ .4 +- .2/sqrt dim

答案 1 :(得分:22)

要计算m乘以距离的矩阵,这应该有效:

>>> 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调用将这些调用转换为相同形状的矩阵(标量欧氏距离)。

答案 2 :(得分:5)

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

对原始问题的直接解决方案确实包括计算每个对之间的距离,然后找到最小值,如果只对最小值感兴趣,则不需要这样做。 / strong>距离。对于后一个问题,存在更快的解决方案。

所有提议的解决方案的运行时间均为m*p = len(xy1)*len(xy2)。这对于小型数据集来说是可以的,但可以编写一个可以扩展为m*log(p)的最佳解决方案,从而为大型xy2数据集节省大量资金。

可以使用scipy.spatial.cKDTree实现此最佳执行时间缩放,如下所示

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)

其中mindistxy1中每个点与xy2中的点集之间的最小距离

答案 3 :(得分:4)

您正在尝试做什么:

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)

编辑:您可以使用sqrt

,而不是调用numpy.hypot,做广场等。
dists = numpy.hypot(xy1[:, 0, numpy.newaxis]-xy2[:, 0], xy1[:, 1, numpy.newaxis]-xy2[:, 1])

答案 4 :(得分:3)

import numpy as np
P = np.add.outer(np.sum(xy1**2, axis=1), np.sum(xy2**2, axis=1))
N = np.dot(xy1, xy2.T)
dists = np.sqrt(P - 2*N)

答案 5 :(得分:0)

我认为以下功能也可以。

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)

说明
假设XY的每一行都是两组点的坐标。
使其大小分别为m X pp X n
结果将生成一个大小为m X n的numpy数组,其中第(i, j)个条目是第i行与第j条之间的距离XY的一行。