首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >向量化Python中重复的数学函数

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

Stack Overflow用户
提问于 2016-02-13 04:18:39
回答 2查看 541关注 0票数 2

我有一个形式为$f(x)=\sum_{j=0}^N x^j * \sin(j*x)$的数学函数,我想用Python高效地计算它。N是~100阶的。对于一个巨大矩阵的所有条目x,这个函数f都会被计算数千次,因此我希望提高性能(profiler表明f的计算占用了大部分时间)。为了避免在函数f的定义中出现循环,我写道:

代码语言:javascript
复制
def f(x)
    J=np.arange(0,N+1)
    return sum(x**J*np.sin(j*x))

问题是,如果我想为矩阵的所有元素计算这个函数,我需要首先使用numpy.vectorize,但据我所知,这不一定比for循环快。

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

EN

回答 2

Stack Overflow用户

发布于 2016-02-13 04:51:38

欢迎来到Sack Overflow!^^

嗯,计算something ** 100是一件很严肃的事情。但请注意,当您声明数组J时,您是如何强制您的函数独立计算x, x^2, x^3, x^4, ... (依此类推)的。

让我们以这个函数为例(这就是您正在使用的函数):

代码语言:javascript
复制
def powervector(x, n):
    return x ** np.arange(0, n)

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

代码语言:javascript
复制
def power(x, n):
    result = [1., x]
    aux = x
    for i in range(2, n):
        aux *= x               
        result.append(aux)
    return result

现在,让我们验证它们是否都计算相同的东西:

代码语言:javascript
复制
In []: sum(powervector(1.1, 10))
Out[]: 15.937424601000005

In []: sum(power(1.1, 10))
Out[]: 15.937424601000009

酷,现在让我们比较一下两者的性能(在iPython中):

代码语言:javascript
复制
In [36]: %timeit sum(powervector(1.1, 10))
The slowest run took 20.42 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 3.52 µs per loop

In [37]: %timeit sum(power(1.1, 10))
The slowest run took 5.28 times longer than the fastest. This could mean that an intermediate result is being cached 
1000000 loops, best of 3: 1.13 µs per loop

它更快,因为你没有计算x的所有能力,因为你知道x ^ N == (x ^ N - 1) * x和你利用它。

您可以使用它来查看您的性能是否有所提高。当然,您可以更改power()以使用NumPy向量作为输出。您还可以看一看Numba,它很容易尝试,并且可能会稍微提高性能。

如您所见,这只是关于如何改进问题的一部分的提示。我敢打赌,还有其他几种方法可以进一步改进您的代码!

编辑

看起来Numba可能不是个坏主意。只需添加@numba.jit装饰器:

代码语言:javascript
复制
@numba.jit
def powernumba(x, n):
    result = [1., x]
    aux = x
    for i in range(2, n):
        aux *= x               
        result.append(aux)
    return result

然后:

代码语言:javascript
复制
In [52]: %timeit sum(power(1.1, 100))
100000 loops, best of 3: 7.67 µs per loop

In [51]: %timeit sum(powernumba(1.1, 100))
The slowest run took 5.64 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 2.64 µs per loop

看起来Numba可以在那里施展魔法。;-)

票数 5
EN

Stack Overflow用户

发布于 2016-02-13 05:46:22

对于标量x

代码语言:javascript
复制
>>> 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本身是一个数组,使用广播:

代码语言:javascript
复制
>>> 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)

然后在第二个轴上求和:

代码语言:javascript
复制
>>> res = a * np.sin(jj * x[:, None])
>>> res.shape
(3, 10)
>>> res.sum(axis=1)
array([ 0.01230993,  0.0613201 ,  0.17154859])
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35371499

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档