无需循环解决广播错误,加快代码速度

时间:2015-05-06 16:36:55

标签: python for-loop numpy matrix scipy

我可能误解了广播如何在Python中运行,但我仍然遇到错误。

scipy提供了许多特殊功能"它包含两个参数,特别是eval_XX(n, x[,out])函数。 见http://docs.scipy.org/doc/scipy/reference/special.html

我的程序使用许多正交多项式,因此我必须在不同的点处评估这些多项式。我们来看具体的例子scipy.special.eval_hermite(n, x, out=None)

我希望x参数为矩阵形(50, 50)。然后,我想在多个点评估该矩阵的每个条目。我们将n定义为一个numpy数组narr = np.arange(10)(我们将numpy导入为np,即import numpy as np)。

所以,请致电

scipy.special.eval_hermite(narr, matrix)

应返回Hermitian多项式H_0(matrix), H_1(matrix), H_2(matrix)等。每个H_X(matrix)的形状为(50,50),即原始输入矩阵的形状。

然后,我想总结这些价值观。所以,我打电话给

matrix1 = np.sum( [scipy.eval_hermite(narr, matrix)], axis=0 )

但是我收到广播错误!

ValueError: operands could not be broadcast together with shapes (10,) (50,50)

我可以用for循环解决这个问题,即

matrix2 = np.sum( [scipy.eval_hermite(i, matrix) for i in narr], axis=0)

这给了我正确的答案和输出matrix2.shape = (50,50)。但是使用这个for循环减慢了我的代码,很长时间。请记住,我们正在使用矩阵条目。

有没有办法在没有for循环的情况下执行此操作?

2 个答案:

答案 0 :(得分:1)

这些函数的文档很少,并且编译了很多代码,所以这只是基于实验:

special.eval_hermite(n, x, out=None)

n显然是一个标量或整数数组。 x可以是浮点数组。

special.eval_hermite(np.ones(5,int)[:,None],np.ones(6))给了我(5,6)个结果。这与我从np.ones(5,int)[:,None] * np.ones(6)得到的形状相同。

np.ones(5,int)[:,None]是一个(5,1)数组,np.ones(6)一个(6,),为此目的相当于(1,6)。两者都可以扩展为(5,6)

我可以说,这些special函数中的广播规则与*等运算符相同。

由于special.eval_hermite(nar[:,None,None], x)生成(10,50,50),您只需将sum应用于其中的{0}即可生成(50,50)

special.eval_hermite(nar[:,Nar,Nar], x).sum(axis=0)

就像我之前写的那样,相同的广播(和求和)规则适用于此hermite,就像*这样的基本操作一样。

答案 1 :(得分:1)

eval_hermite使用n广播x,然后在每个点评估H n (x)。因此,输出形状将是使用n广播x的结果。因此,如果您想要完成这项工作,则必须使nx具有兼容的形状:

import scipy.special as ss
import numpy as np
matrix = np.ones([100,100]) # example
narr = np.arange(10) # example
ss.eval_hermite(narr[:,None,None], matrix).shape # => (10, 100, 100)

但请注意,这实际上可能更快:

out = np.zeros_like(matrix)
for n in narr:
    out += ss.eval_hermite(n, matrix)

在测试中,它似乎比上述np.sum(...)快5-10%。