在 python 中是否有类似于 scipy.spatial.distance.cdist 的东西但用于位移(快速)?

In python is there something similar to scipy.spatial.distance.cdist but for displacements (fast)?

我已经研究了几个星期的代码,并且一直在尝试通过使用 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 函数更快。

谢谢!

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

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

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