提高性能以实现价值回报



对于这种类型的评估结构,如何提高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调用。

最新更新