python中最快的成对距离度量

python中最快的成对距离度量,python,arrays,numpy,scipy,scikit-learn,Python,Arrays,Numpy,Scipy,Scikit Learn,我有一个一维的数字数组,我想计算所有成对的欧几里德距离。我有一种方法(幸亏如此)可以通过广播来实现这一点,但它效率很低,因为它会计算两次每个距离。而且它的伸缩性不好 下面是一个例子,它给出了我想要的1000个数字的数组 import numpy as np import random r = np.array([random.randrange(1, 1000) for _ in range(0, 1000)]) dists = np.abs(r - r[:, None]) scipy/num

我有一个一维的数字数组,我想计算所有成对的欧几里德距离。我有一种方法(幸亏如此)可以通过广播来实现这一点,但它效率很低,因为它会计算两次每个距离。而且它的伸缩性不好

下面是一个例子,它给出了我想要的1000个数字的数组

import numpy as np
import random
r = np.array([random.randrange(1, 1000) for _ in range(0, 1000)])
dists = np.abs(r - r[:, None])
scipy/numpy/scikit中最快的实现是什么?我可以使用它来实现这一点,因为它必须扩展到1D数组的值大于10k的情况


注意:矩阵是对称的,所以我猜通过解决这个问题,至少可以获得2倍的加速,我只是不知道如何实现。

这里有一个Cython实现,在我的计算机上,这个例子的速度提高了3倍多。对于更大的数组,应该检查这个时间安排,因为BLAS例程可能比这个简单的代码扩展得更好

我知道您要求在scipy/numpy/scikit learn中提供一些内容,但这可能会为您带来新的可能性:

文件
my\u cython.pyx

import numpy as np
cimport numpy as np
import cython

cdef extern from "math.h":
    double abs(double t)

@cython.wraparound(False)
@cython.boundscheck(False)
def pairwise_distance(np.ndarray[np.double_t, ndim=1] r):
    cdef int i, j, c, size
    cdef np.ndarray[np.double_t, ndim=1] ans
    size = sum(range(1, r.shape[0]+1))
    ans = np.empty(size, dtype=r.dtype)
    c = -1
    for i in range(r.shape[0]):
        for j in range(i, r.shape[0]):
            c += 1
            ans[c] = abs(r[i] - r[j])
    return ans
答案是包含所有非重复计算的一维数组

要导入Python,请执行以下操作:

import numpy as np
import random

import pyximport; pyximport.install()
from my_cython import pairwise_distance

r = np.array([random.randrange(1, 1000) for _ in range(0, 1000)], dtype=float)

def solOP(r):
    return np.abs(r - r[:, None])
使用IPython进行计时:

In [2]: timeit solOP(r)
100 loops, best of 3: 7.38 ms per loop

In [3]: timeit pairwise_distance(r)
1000 loops, best of 3: 1.77 ms per loop
In [36]: timeit option1(r)
100 loops, best of 3: 5.31 ms per loop

In [37]: timeit option2(c)
1000 loops, best of 3: 1.84 ms per loop

In [38]: timeit option3(c)
100 loops, best of 3: 11.5 ms per loop

使用一半的内存,但比
np.abs(r-r[:,None])慢6倍


其他两个答案都没有完全回答这个问题-1是在赛昂,一个比较慢。但两者都提供了非常有用的提示。对他们的跟踪表明,
scipy.space.distance.pdist
是一条可行之路

下面是一些代码:

import numpy as np
import random
import sklearn.metrics.pairwise
import scipy.spatial.distance

r = np.array([random.randrange(1, 1000) for _ in range(0, 1000)])
c = r[:, None]

def option1(r):
    dists = np.abs(r - r[:, None])

def option2(r):
    dists = scipy.spatial.distance.pdist(r, 'cityblock')

def option3(r):
    dists = sklearn.metrics.pairwise.manhattan_distances(r)
使用IPython进行计时:

In [2]: timeit solOP(r)
100 loops, best of 3: 7.38 ms per loop

In [3]: timeit pairwise_distance(r)
1000 loops, best of 3: 1.77 ms per loop
In [36]: timeit option1(r)
100 loops, best of 3: 5.31 ms per loop

In [37]: timeit option2(c)
1000 loops, best of 3: 1.84 ms per loop

In [38]: timeit option3(c)
100 loops, best of 3: 11.5 ms per loop

我没有尝试Cython实现(我不能在这个项目中使用它),但将我的结果与另一个答案进行比较,它看起来比Cython实现慢大约三分之一(通过在np.abs解决方案上进行基准测试,考虑到不同的机器).

这有一个函数:。我不知道这是否是最快的选择,因为它需要检查多维数据、非欧几里得规范和其他东西,但它是内置的。你需要多快?它的伸缩性永远不会比O(n^2)更好,因为您必须填充n^2个输出条目。您现有的解决方案是O(n^2),并且似乎没有太大的空间进行重大优化。当我尝试它时,这似乎已经足够扩展到>10k的值。请记住,您需要填充1亿个输出条目。这几乎是半千兆字节的成对距离。@askewchan我不认为它有。。。如果您遵循源代码,最终将调用函数。不仅没有奇特的优化,而且对于一维向量,它是平方和取平方根来计算绝对值。可能比OP的特定用例的代码更糟糕。@CTZhu如果我没有弄错的话,
scipy
总是用BLAS编译的,它不像
numpy
那样是可选的。你肯定是说
fabs
-
abs
int
变体。我想这和:?sklearn中的版本?在scipy.spatial.distance.pdist的情况下,应该是c而不是r吗?