我一直在浏览这些问题,并且可以找到一些帮助,但我更喜欢直接询问确认。所以这是我的问题。
我有一个维度为N的(numpy)数组u
,我想从中建立一个维数为N ^ 2的方阵k
。基本上,每个矩阵元素k(i,j)
都定义为k(i,j)=exp(-|u_i-u_j|^2)
。
我的第一个天真的方式是这样的,我相信,就像Fortran一样:
for i in range(N):
for j in range(N):
k[i][j]=np.exp(np.sum(-(u[i]-u[j])**2))
但是,这非常慢。例如,对于N = 1000,它需要大约15秒。 我要采取的另一种方式是(受其他问题/答案的启发):
i, j = np.ogrid[:N,:N]
k = np.exp(np.sum(-(u[i]-u[j])**2,axis=2))
这样更快,因为N = 1000,结果几乎是瞬时的。 所以我有两个问题。
1)为什么第一种方法如此之慢,为什么第二种方法如此之快?
2)有更快的方法吗?对于N = 10000,它已经开始花了相当长的时间,所以我真的不知道这是不是"对"这样做的方法。
提前谢谢!
PS:矩阵是对称的,所以还必须有一种方法通过仅计算矩阵的上半部分来加快处理速度,但我的问题与操纵数组的方式等有关。
答案 0 :(得分:1)
首先,一句小话,如果np.sum
可以重写为u
,则无需使用u = np.arange(N)
。这似乎就是这种情况,因为你写的它是维度N
。
1)第一个问题:
在Python中访问索引很慢,所以如果有办法不使用它,最好不要使用[]。另外,您可以多次调用np.exp
和np.sum
,而可以调用矢量和矩阵。因此,您的第二个提案更好,因为您一次计算k
所有内容,而不是按元素计算元素。
2)第二个问题: 就在这里。您应该考虑仅使用numpy函数而不使用索引(大约快3倍):
k = np.exp(-np.power(np.subtract.outer(u,u),2))
(注意:您可以保留**2
而不是np.power
,这有点快,但精度较低)
修改(考虑到u
是一个元组数组)
使用元组数据,它有点复杂:
ma = np.subtract.outer(u[:,0],u[:,0])**2
mb = np.subtract.outer(u[:,1],u[:,1])**2
k = np.exp(-np.add(ma, mb))
您必须使用两次np.substract.outer
,因为如果您一次执行它会返回一个4维数组(并计算大量无用数据),而u[i]-u[j]
则返回3维度数组。
我使用np.add
代替np.sum
,因为它保留了数组维度。
注意:我用
检查了N = 10000
u = np.random.random_sample((N,2))
我返回与您的提案相同的内容。 (但快1.7倍)