在Python中构建矩阵的快速方法

时间:2017-06-26 11:28:38

标签: python performance numpy matrix

我一直在浏览这些问题,并且可以找到一些帮助,但我更喜欢直接询问确认。所以这是我的问题。

我有一个维度为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:矩阵是对称的,所以还必须有一种方法通过仅计算矩阵的上半部分来加快处理速度,但我的问题与操纵数组的方式等有关。

1 个答案:

答案 0 :(得分:1)

首先,一句小话,如果np.sum可以重写为u,则无需使用u = np.arange(N)。这似乎就是这种情况,因为你写的它是维度N

1)第一个问题: 在Python中访问索引很慢,所以如果有办法不使用它,最好不要使用[]。另外,您可以多次调用np.expnp.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倍)