1

我已经研究了几个星期的代码,并试图通过使用 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 个数量级)——但这只会给出正值。即实际上,我必须计算这 15,000 次,其中 a 有 1,000 个元素,所以那些 2oom 很重要。

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

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

我希望你们可以对我如何做一些事情来从 cdist 创建所需的签名输出提出建议,但比使用 lambda 函数更快。

谢谢!

4

1 回答 1

0

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

对于您的特定情况,数据在哪里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)

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

于 2020-03-06T15:39:30.980 回答