对于这种类型的评估结构,如何提高G(x,y)的性能:
from scipy import integrate,infty
def f(x):
"""
Some complicated function
"""
pass
def F(x):
"""
Integration of f
"""
value = integrate.quad(f,-infty,x)
return value
def g(x,y):
"""
Another complicated function which uses F(x)!
"""
pass
def G(x,y):
"""
The function for which I want to improve perfomance
"""
value = integrate.quad(g,-infty,+infty,args=(y))
return value
我想要的是用以前做过的F(x)评估的参考来代替它。
编辑
为了清晰起见,使用了scipy.interpolate.interp1d
和decorator之后,我的代码看起来像:
class interpolate_function():
"""
Returns interpolated function in given range
"""
def __init__(self,tmin=-20,tmax=+20):
self.tmin = tmin
self.tmax = tmax
def __call__(self,expX):
tmin = self.tmin
tmax = self.tmax
from numpy import linspace
t = linspace(tmin,tmax,2000)
import scipy.interpolate as inter
#expX_interp = inter.PchipInterpolator(t,W.expX(t))
from scipy import vectorize
expX = vectorize(expX)
expX_interp = inter.interp1d(t,expX(t),kind='linear')
return expX_interp
from scipy import integrate,infty
def f(x):
"""
Some complicated function
"""
pass
@interpolate_function(tmin=-20,tmax=+20)
def F(x):
"""
Integration of f
"""
value = integrate.quad(f,-infty,x)
return value
def g(x,y):
"""
Another complicated function which uses F(x)!
"""
pass
def G(x,y):
"""
The function for which I want to improve perfomance
"""
value = integrate.quad(g,-infty,+infty,args=(y))
return value
因此,除了decorator之外,主代码保持不变,但性能提高了3000倍左右。
对于每次对F(x)
的调用,您都在(-ninfinity,x)中进行集成,这是您的瓶颈。相反,我会对一组点进行积分,并创建一个插值函数。因此,如果x
的值在0和10之间,则可以执行从-无穷大到0、0.5…9.5、10的积分(根据需要使用薄网格),并对其进行插值。
编辑:
为了更有效地构建网格,可以使用积分的加法性质。因此,F(0)=int_infty^0 F(x),F(1)=F(0。此外,为了避免奇怪的插值效应,我会使用pchip
(埃尔米特多项式,总是在边界中达到最大值和最小值)或线性插值。
实现这一点的典型方法是"内存化",使用装饰器:
def memo(f):
cache = {}
def func(*args):
if args not in cache:
cache[args] = f(*args)
return cache[args]
return func
@memo
def F(x):
"""
Integration of f
"""
value = integrate.quad(f,-infty,x)
return value
现在,无论何时调用F(x)
,实际上都是在调用func(x)
,如果已经针对x
的值对F
进行了求值,那么它将直接从cache
返回,而不是再次调用F
。
请注意,正如Davidmh所指出的,这是用速度换取空间;您必须存储以前评估的所有结果。此外,只有在多次评估完全相同的x
值时,您才能获得好处。
根据我的经验,在numpy/scipy中优化效率的关键是最大限度地减少python代码的执行量。如果可能的话,任何循环都不应该作为python循环进行,而应该作为矩阵向量运算或类似操作进行;本质上,您希望将循环移动到numpy/scipy库中。
在您的情况下,我会尽量避免从g
调用其他python函数,并尝试将其编写为一系列短的numpy/scipy调用。