Python中的向量化重复数学函数

Python中的向量化重复数学函数,python,numpy,vectorization,mathematical-expressions,Python,Numpy,Vectorization,Mathematical Expressions,我有一个数学函数,它的形式是$f(x)=\sum{j=0}^nx^j*\sin(j*x)$,我想用Python高效地计算它。N的数量级为~100。对于一个巨大矩阵的所有条目x,该函数f被求值数千次,因此我想提高性能(探查器表明,f的计算占用了大部分时间)。为了避免函数f定义中的循环,我写了: def f(x) J=np.arange(0,N+1) return sum(x**J*np.sin(j*x)) 问题是,如果我想为矩阵的所有条目计算此函数,我需要首先使用numpy.ve

我有一个数学函数,它的形式是
$f(x)=\sum{j=0}^nx^j*\sin(j*x)$
,我想用
Python
高效地计算它。N的数量级为~100。对于一个巨大矩阵的所有条目x,该函数f被求值数千次,因此我想提高性能(探查器表明,f的计算占用了大部分时间)。为了避免函数f定义中的循环,我写了:

def f(x)
    J=np.arange(0,N+1)
    return sum(x**J*np.sin(j*x))
问题是,如果我想为矩阵的所有条目计算此函数,我需要首先使用
numpy.vectorize
,但据我所知,这并不一定比for循环快


有没有一种有效的方法来执行这种类型的计算?

欢迎使用Sack Overflow^^

嗯,计算某物**100是一件严肃的事情。但是请注意,当您声明数组
J
时,您是如何强制函数独立地计算
x、x^2、x^3、x^4、
(等等)

让我们以该函数为例(您正在使用该函数):

现在还有一个函数,它甚至不使用NumPy:

def power(x, n):
    result = [1., x]
    aux = x
    for i in range(2, n):
        aux *= x               
        result.append(aux)
    return result
现在,让我们验证一下,它们都计算了相同的东西:

In []: sum(powervector(1.1, 10))
Out[]: 15.937424601000005

In []: sum(power(1.1, 10))
Out[]: 15.937424601000009
很酷,现在让我们比较一下这两种方法的性能(在iPython中):

它更快,因为您没有计算
x
的所有幂,因为您知道
x^N==(x^N-1)*x
,您可以利用它

你可以用这个来看看你的表现是否有所改善。当然,您可以更改
power()
以使用NumPy向量作为输出。您还可以看一看,这很容易尝试,也可以稍微提高性能

正如您所看到的,这只是一个提示,说明如何改进问题的某些方面。我打赌还有其他几种方法可以进一步改进您的代码!:-)

编辑 看来麻木可能不是个坏主意。。。只需添加
@numba.jit
装饰器:

@numba.jit
def powernumba(x, n):
    result = [1., x]
    aux = x
    for i in range(2, n):
        aux *= x               
        result.append(aux)
    return result
然后:


似乎麻麻可以在那里施展魔法

对于标量
x

>>> import numpy as np
>>> x = 0.5
>>> jj = np.arange(10)
>>> x**jj
array([ 1.        ,  0.5       ,  0.25      ,  0.125     ,  0.0625    ,
        0.03125   ,  0.015625  ,  0.0078125 ,  0.00390625,  0.00195312])
>>> np.sin(jj*x)
array([ 0.        ,  0.47942554,  0.84147098,  0.99749499,  0.90929743,
        0.59847214,  0.14112001, -0.35078323, -0.7568025 , -0.97753012])
>>> (x**jj * np.sin(jj*x)).sum()
0.64489974041068521
注意numpy数组的
sum
方法的使用(等效地,使用
np.sum
不是内置的
sum

如果
x
本身是一个数组,请使用广播:

>>> a = x[:, None]**jj
>>> a.shape
(3, 10)
>>> x[0]**jj == a[0]
array([ True,  True,  True,  True,  True,  True,  True,  True,  True,  True], dtype=bool)
然后在第二个轴上求和:

>>> res = a * np.sin(jj * x[:, None])
>>> res.shape
(3, 10)
>>> res.sum(axis=1)
array([ 0.01230993,  0.0613201 ,  0.17154859])

这是一个好主意,我一定会按照这些思路实施一些东西。然而,在将来,对于某些函数g,我希望用类似sum_{j=0}^N g(x,C)的东西来替换表达式,因此我试图寻找一种更通用的方法来改进代码,而不管函数g如何。@PythonBeginner:Numba仍然适用于这种情况。看看那个项目,你不会后悔的!;-)我第一次听说麻麻,我会看一看:)
>>> import numpy as np
>>> x = 0.5
>>> jj = np.arange(10)
>>> x**jj
array([ 1.        ,  0.5       ,  0.25      ,  0.125     ,  0.0625    ,
        0.03125   ,  0.015625  ,  0.0078125 ,  0.00390625,  0.00195312])
>>> np.sin(jj*x)
array([ 0.        ,  0.47942554,  0.84147098,  0.99749499,  0.90929743,
        0.59847214,  0.14112001, -0.35078323, -0.7568025 , -0.97753012])
>>> (x**jj * np.sin(jj*x)).sum()
0.64489974041068521
>>> a = x[:, None]**jj
>>> a.shape
(3, 10)
>>> x[0]**jj == a[0]
array([ True,  True,  True,  True,  True,  True,  True,  True,  True,  True], dtype=bool)
>>> res = a * np.sin(jj * x[:, None])
>>> res.shape
(3, 10)
>>> res.sum(axis=1)
array([ 0.01230993,  0.0613201 ,  0.17154859])