在两个不同的阵列numpy的点之间的最小欧几里得距离,而不是内

问题描述 投票:38回答:5

我的X-Y坐标的两个阵列,我想找到的每个点之间的最小欧几里得距离中一个阵列与另一阵列中的所有点。该阵列是不一定相同的尺寸。例如:

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)和I存储原始阵列的长度。从理论上说,我应该然后能够产生从从中我可以抓住的M×p子矩阵的那些坐标的N×N的距离矩阵。有没有一种方法能够有效地产生这种子矩阵?

python numpy euclidean-distance
5个回答
40
投票

(几个月后)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

24
投票

为了计算的距离的P矩阵为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呼叫接通那些成相同形状的矩阵(标量欧几里德距离的)。


5
投票

对于你想要做什么:

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])

5
投票

接受的答案不能完全解决问题,它要求以发现两套点之间的最小距离,而不是两套每个点之间的距离。

Altough一个直接的解决方案,以原来的问题确实包括计算每对之间的距离和susequently找到最小的一个的,如果一个是只在最小距离感兴趣的,这是没有必要的。更快的解决方案存在后一个问题。

所有提出的解决方案,它可以扩展为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点之间的最小距离


4
投票
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)
© www.soinside.com 2019 - 2024. All rights reserved.