我已经研究了几个星期的代码,并试图通过使用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)
对于对称距离测量,一半的计算是不必要的。但根据我的经验,它仍然比试图仅将计算应用于上三角形或类似的东西更快。