python中最快的成对距离度量

rob*_*anf 13 python arrays numpy scipy scikit-learn

我有一维数字,想要计算所有成对的欧氏距离.我有一个方法(感谢SO)用广播这样做,但它效率低,因为它计算每个距离两次.并且它不能很好地扩展.

这是一个例子,通过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])
Run Code Online (Sandbox Code Playgroud)

什么是scipy/numpy/scikit中最快的实现 - 我可以用来做这个,因为它必须扩展到1D数组具有> 10k值的情况.

注意:矩阵是对称的,所以我猜测通过解决它可以获得至少2倍的加速,我只是不知道如何.

rob*_*anf 21

其他答案都没有回答这个问题 - 一个是在Cython中,一个是慢的.但两者都提供了非常有用的提示.跟进他们表明这scipy.spatial.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)
Run Code Online (Sandbox Code Playgroud)

使用IPython进行计时:

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
Run Code Online (Sandbox Code Playgroud)

我没有尝试过Cython实现(我不能将它用于这个项目),但是将我的结果与其他答案进行比较,它看起来scipy.spatial.distance.pdist比Cython实现慢了大约三分之一(考虑到不同的机器)通过对np.abs解决方案进行基准测试).


Sau*_*tro 5

这是一个Cython实现,在我的计算机上为这个例子提供了超过3倍的速度提升.对于更大的阵列,应该检查这个时序,因为BLAS例程可能比这个相当天真的代码更好地扩展.

我知道你要求scipy/numpy/scikit-learn里面的东西,但也许这会给你带来新的可能性:

档案my_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
Run Code Online (Sandbox Code Playgroud)

答案是包含所有非重复评估的一维数组.

要导入到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])
Run Code Online (Sandbox Code Playgroud)

使用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
Run Code Online (Sandbox Code Playgroud)


cyb*_*org 5

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

triu = np.triu_indices(r.shape[0],1)
dists2 = abs(r[triu[1]]-r[triu[0]])
Run Code Online (Sandbox Code Playgroud)