识别具有最小欧氏距离的点

发布于 2024-10-19 00:43:02 字数 574 浏览 6 评论 0原文

我有一个 n 维点的集合,我想找到哪 2 个最接近。我能想到的最好的二维是:

from numpy import *
myArr = array( [[1, 2],
                [3, 4],
                [5, 6],
                [7, 8]] )

n = myArr.shape[0]
cross = [[sum( ( myArr[i] - myArr[j] ) ** 2 ), i, j]
         for i in xrange( n )
         for j in xrange( n )
         if i != j
         ]

print min( cross )

这给出了

[8, 0, 1]

但这对于大型数组来说太慢了。我可以对其应用什么样的优化?

相关:


两个不同 Numpy 数组中的点之间的欧几里得距离,不在范围内

I have a collection of n dimensional points and I want to find which 2 are the closest. The best I could come up for 2 dimensions is:

from numpy import *
myArr = array( [[1, 2],
                [3, 4],
                [5, 6],
                [7, 8]] )

n = myArr.shape[0]
cross = [[sum( ( myArr[i] - myArr[j] ) ** 2 ), i, j]
         for i in xrange( n )
         for j in xrange( n )
         if i != j
         ]

print min( cross )

which gives

[8, 0, 1]

But this is too slow for large arrays. What kind of optimisation can I apply to it?

RELATED:


Euclidean distance between points in two different Numpy arrays, not within

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

万水千山粽是情ミ 2024-10-26 00:43:02

尝试 scipy.spatial.distance.pdist(myArr) 。这将为您提供一个压缩距离矩阵。您可以对其使用 argmin 并找到最小值的索引。这可以被转换成配对信息。

Try scipy.spatial.distance.pdist(myArr). This will give you a condensed distance matrix. You can use argmin on it and find the index of the smallest value. This can be converted into the pair information.

貪欢 2024-10-26 00:43:02

关于这个问题有一个完整的维基百科页面,请参阅:http://en.wikipedia.org/wiki/Closest_pair_of_points

摘要:您可以使用递归分治算法实现 O(n log n)(在上面的 Wiki 页面上概述)。

There's a whole Wikipedia page on just this problem, see: http://en.wikipedia.org/wiki/Closest_pair_of_points

Executive summary: you can achieve O(n log n) with a recursive divide and conquer algorithm (outlined on the Wiki page, above).

梅窗月明清似水 2024-10-26 00:43:02

您可以利用最新版本的 SciPy (v0.9) Delaunay 三角测量工具。您可以确定最近的两个点将是三角剖分中单纯形的边,这是比执行每个组合要小得多的对的子集。

这是代码(针对一般 ND 进行了更新):

import numpy
from scipy import spatial

def closest_pts(pts):
    # set up the triangluataion
    # let Delaunay do the heavy lifting
    mesh = spatial.Delaunay(pts)

    # TODO: eliminate reduncant edges (numpy.unique?)
    edges = numpy.vstack((mesh.vertices[:,:dim], mesh.vertices[:,-dim:]))

    # the rest is easy
    x = mesh.points[edges[:,0]]
    y = mesh.points[edges[:,1]]

    dists = numpy.sum((x-y)**2, 1)
    idx = numpy.argmin(dists)

    return edges[idx]
    #print 'distance: ', dists[idx]
    #print 'coords:\n', pts[closest_verts]

dim = 3
N = 1000*dim
pts = numpy.random.random(N).reshape(N/dim, dim)

看起来很接近 O(n):

在此处输入图像描述

You could take advantage of the latest version of SciPy's (v0.9) Delaunay triangulation tools. You can be sure that the closest two points will be an edge of a simplex in the triangulation, which is a much smaller subset of pairs than doing every combination.

Here's the code (updated for general N-D):

import numpy
from scipy import spatial

def closest_pts(pts):
    # set up the triangluataion
    # let Delaunay do the heavy lifting
    mesh = spatial.Delaunay(pts)

    # TODO: eliminate reduncant edges (numpy.unique?)
    edges = numpy.vstack((mesh.vertices[:,:dim], mesh.vertices[:,-dim:]))

    # the rest is easy
    x = mesh.points[edges[:,0]]
    y = mesh.points[edges[:,1]]

    dists = numpy.sum((x-y)**2, 1)
    idx = numpy.argmin(dists)

    return edges[idx]
    #print 'distance: ', dists[idx]
    #print 'coords:\n', pts[closest_verts]

dim = 3
N = 1000*dim
pts = numpy.random.random(N).reshape(N/dim, dim)

Seems closely O(n):

enter image description here

一个人的旅程 2024-10-26 00:43:02

有一个 scipy 函数 pdist 可以以相当有效的方式获取数组中点之间的成对距离:

http://docs.scipy.org/doc/scipy/reference/spatial.distance.html

输出 N*(N-1)/ 2 个唯一对(因为 r_ij == r_ji)。然后,您可以搜索最小值并避免代码中的整个循环混乱。

There is a scipy function pdist that will get you the pairwise distances between points in an array in a fairly efficient manner:

http://docs.scipy.org/doc/scipy/reference/spatial.distance.html

that outputs the N*(N-1)/2 unique pairs (since r_ij == r_ji). You can then search on the minimum value and avoid the whole loop mess in your code.

或十年 2024-10-26 00:43:02

也许您可以沿着这些思路继续进行:

In []: from scipy.spatial.distance import pdist as pd, squareform as sf
In []: m= 1234
In []: n= 123
In []: p= randn(m, n)
In []: d= sf(pd(p))
In []: a= arange(m)
In []: d[a, a]= d.max()
In []: where(d< d.min()+ 1e-9)
Out[]: (array([701, 730]), array([730, 701]))

有了更多的点,您需要能够以某种方式利用集群的层次结构。

Perhaps you could proceed along these lines:

In []: from scipy.spatial.distance import pdist as pd, squareform as sf
In []: m= 1234
In []: n= 123
In []: p= randn(m, n)
In []: d= sf(pd(p))
In []: a= arange(m)
In []: d[a, a]= d.max()
In []: where(d< d.min()+ 1e-9)
Out[]: (array([701, 730]), array([730, 701]))

With substantially more points you need to be able to somehow utilize the hierarchical structure of your clustering.

月牙弯弯 2024-10-26 00:43:02

与仅执行嵌套循环并跟踪最短对相比,它有多快?我认为创建一个巨大的交叉数组可能会伤害你。如果你只处理二维点,即使 O(n^2) 仍然相当快。

How fast is it compared to just doing a nested loop and keeping track of the shortest pair? I think creating a huge cross array is what might be hurting you. Even O(n^2) is still pretty quick if you're only doing 2 dimensional points.

弥枳 2024-10-26 00:43:02

对于小型数据集,接受的答案是可以的,但其执行时间为 n**2。然而,正如 @payne 所指出的,最佳解决方案可以实现 n*log(n) 计算时间缩放。

这个最佳解决方案可以使用 sklearn.neighbors.BallTree如下。

import matplotlib.pyplot as plt
import numpy as np
from sklearn.neighbors import BallTree as tree

n = 10
dim = 2
xy = np.random.uniform(size=[n, dim])

# This solution is optimal when xy is very large
res = tree(xy)
dist, ids = res.query(xy, 2)
mindist = dist[:, 1]  # second nearest neighbour
minid = np.argmin(mindist)

plt.plot(*xy.T, 'o')
plt.plot(*xy[ids[minid]].T, '-o')

对于非常大的 xy 值集,甚至对于大尺寸 dim(尽管示例说明了 dim=2 的情况),此过程可以很好地扩展。结果输出如下所示

最近的一对点由橙色线连接

使用 scipy.spatial.cKDTree,通过将 sklearn 导入替换为以下 Scipy 导入。但请注意,与 BallTree 不同,cKDTree 不能很好地适应高维度

from scipy.spatial import cKDTree as tree

The accepted answer is OK for small datasets, but its execution time scales as n**2. However, as pointed out by @payne, an optimal solution can achieve n*log(n) computation time scaling.

This optial solution can be obtained using sklearn.neighbors.BallTree as follows.

import matplotlib.pyplot as plt
import numpy as np
from sklearn.neighbors import BallTree as tree

n = 10
dim = 2
xy = np.random.uniform(size=[n, dim])

# This solution is optimal when xy is very large
res = tree(xy)
dist, ids = res.query(xy, 2)
mindist = dist[:, 1]  # second nearest neighbour
minid = np.argmin(mindist)

plt.plot(*xy.T, 'o')
plt.plot(*xy[ids[minid]].T, '-o')

This procedure scales well for very large sets of xy values and even for large dimensions dim (altough the example illustrates the case dim=2). The resulting output looks like this

The nearest pair of points is connected by an orange line

An identical solution can be obtained using scipy.spatial.cKDTree, by replacing the sklearn import with the following Scipy one. Note however that cKDTree, unlike BallTree, does not scale well for high dimensions

from scipy.spatial import cKDTree as tree
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文