在python中,除了位移(fast)之外,还有类似于scipy.spatial.distance.cdist的东西吗



我已经研究了几个星期的代码,并试图通过使用cdist而不是多级for循环来计算矩阵中每个点之间的距离来加快速度。

我想要什么:

from scipy.spatial.distance import cdist
import numpy as np
a=np.array([[1],[2],[3]])
cdist(a,a, lambda u,v: u-v)
[[ 0. -1. -2.]
[ 1.  0. -1.]
[ 2.  1.  0.]]

然而,我的问题是,在我的研究中,a相当大,在cdist中使用自定义lambda函数比cdist(a,a(慢得多(约2个数量级(,但这只会给出正值。事实上,当a有1000个元素时,我必须计算15000次,所以这2个元素很重要。

注意cdist(a,a(没有给出所需的输出,因为它都是正值。

[[0. 1. 2.]
[1. 0. 1.]
[2. 1. 0.]]

我希望你们能对我如何从cdist创建所需的签名输出提出建议,但要比使用lambda函数更快。

谢谢!

根据您的距离度量和数据类型,您有不同的选择:

对于数据为1D|u-v| == ( (u-v)^2 )^(1/2)的特定情况,您可以使用您的知识,即距离矩阵的上三角和下三角在绝对值上相等,并且只在符号上不同,因此您可以避免自定义距离函数:

d = cdist(a, a)
triu_bool = np.triu(np.ones((n_samples, n_samples), dtype=bool))
triu_bool[range(n_samples), range(n_samples)] = False
d[triu_bool] *= -1
# [[ 0. -1. -2.]
#  [ 1.  0. -1.]
#  [ 2.  1.  0.]]

更一般,在我看来更好的方法是简单地使用numpys广播(另请参阅此问题/答案(。这里是u-v:的一个例子

# Generate data
n_dim = 3
n_samples = int(1.5e4)
arr = np.concatenate([np.arange(n_samples)[:, np.newaxis]] * n_dim, axis=-1)
# array([[    0,     0,     0],
#        [    1,     1,     1],
#        [    2,     2,     2],
#        ...,
#        [14997, 14997, 14997],
#        [14998, 14998, 14998],
#        [14999, 14999, 14999]])
# u - v
d = arr[:, np.newaxis, :] - arr[np.newaxis, :, :]
# (n_samples, n_samples, n_dim)

对于对称距离测量,一半的计算是不必要的。但根据我的经验,它仍然比试图仅将计算应用于上三角形或类似的东西更快。

最新更新