【问题标题】:In python is there something similar to scipy.spatial.distance.cdist but for displacements (fast)?在 python 中是否有类似于 scipy.spatial.distance.cdist 但用于位移(快速)的东西?
【发布时间】:2020-03-06 14:54:15
【问题描述】:

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

谢谢!

【问题讨论】:

  • 这解决了我的问题 - 我将其标记为已解决。谢谢!

标签: python numpy scipy scipy-spatial


【解决方案1】:

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

对于您的具体情况,如果数据是 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 广播(see also this question/answer)。 这里以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)

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-03-15
    • 1970-01-01
    • 1970-01-01
    • 2011-12-04
    • 2011-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多