我怎样才能加快 scipy.integrate.quad?
How can I speed up scipy.integrate.quad?
考虑以下代码:
def disFunc(x,n):
y = np.power(x, n-1)*np.exp(-x)
return y
def disFunc2(t,n,beta):
y = integrate.quad(disFunc, a = 0, b = beta*t, args = (n))
return y[0]
def disFunc3(func):
y = np.vectorize(func)
return(y)
maxCounter = 6000
stepSize = .001
n = 5
beta = 25
t = np.cumsum(np.ones(maxCounter)*stepSize)-stepSize
x = disFunc3(disFunc2)
start_time = time.time()
y = x(t,n,beta)
time_taken = (time.time() - start_time)
print (time_taken)
效果很好,但速度太慢(1.85 秒)。我怎样才能加快速度?
首先,np.vectorize
通常很慢。也许您可以尝试更改您的代码以不必依赖它。
否则,你可以试试Numba
/Numba-Scipy
的jit(即时编译)。这显着加快了使用 NumPy 和 Scipy 的代码:
http://numba.pydata.org/
然后您可以导入 jit 装饰器,并在您的函数中使用它:
from numba import jit
@jit # or jit(nopython=False) in other scenarios
def disFunc(x,n):
y = np.power(x, n-1)*np.exp(-x)
return y
> ...
确保同时安装 Numba 和 Numba-Scipy!
如果你只是想集成你在这里给出的功能:
请注意,您希望积分的函数实际上等同于 Lower Incomplete Gamma Function. scipy
includes the scipy.special.gammainc
函数,用于逼近下不完全 Gamma 函数,由(完整)Gamma 函数正则化(即:其输出除以 Gamma( n)).因此,我们可以使用这些专用函数更有效地近似积分:
from scipy import special
import time
# ...
start_time = time.time()
y = special.gammainc(n, beta * t)
y *= special.gamma(n) # Reverse the regularisation
time_taken = (time.time() - start_time)
print(time_taken)
print(y)
所需的时间会因 n 的不同值而异,但对于 n = 5.5,此 运行 在我的机器上用时约 0.0005 秒,而下面的方法为 0.3 秒。
如果要集成不存在封闭形式的任意函数:
这里有一个想法,它只是改进了您在数学上使用的方法,而不是使用 JIT 编译。这 运行s 在我的机器上快了 ~10 倍(你的代码对我来说需要 ~2.2 秒到 运行,这需要 ~0.3 秒):
import numpy as np
from scipy import integrate
import time
def disFunc(x, n):
y = np.power(x, n - 1) * np.exp(-x)
return y
def disFunc2(t_prev, t_cur, n, beta):
y = integrate.quad(disFunc, a=beta * t_prev, b=beta * t_cur, args=(n))
return y[0]
def disFunc3(func):
y = np.vectorize(func)
return y
maxCounter = 6000
stepSize = 0.001
n = 5
beta = 25
t = np.cumsum(np.ones(maxCounter) * stepSize) - stepSize
x = disFunc3(disFunc2)
start_time = time.time()
y = x(t[:-1], t[1:], n, beta)
time_taken = time.time() - start_time
print(time_taken)
print(np.cumsum(y))
这个想法使用了积分的性质:a 运行ge [a, b] 上的积分等价于 [a, c] 上的积分加上 [c, b] 上的积分,对于a和b之间的一些c。因此,我们不是每次都计算 (0, b * t) 之间的积分,而是只计算 (b * prev_t, b * t) 之间的积分(其中 prev_t 是我们使用的最后一个 t ),然后 运行 一个累加和。这只会让它更快,因为在较小的 运行ge.
上执行积分所需的近似迭代次数要少得多
需要注意的是,这确实跳过了第一个积分(从 0 到 beta * t[0]),因此您可能需要单独计算它并将其添加到数组的前面。
考虑以下代码:
def disFunc(x,n):
y = np.power(x, n-1)*np.exp(-x)
return y
def disFunc2(t,n,beta):
y = integrate.quad(disFunc, a = 0, b = beta*t, args = (n))
return y[0]
def disFunc3(func):
y = np.vectorize(func)
return(y)
maxCounter = 6000
stepSize = .001
n = 5
beta = 25
t = np.cumsum(np.ones(maxCounter)*stepSize)-stepSize
x = disFunc3(disFunc2)
start_time = time.time()
y = x(t,n,beta)
time_taken = (time.time() - start_time)
print (time_taken)
效果很好,但速度太慢(1.85 秒)。我怎样才能加快速度?
首先,np.vectorize
通常很慢。也许您可以尝试更改您的代码以不必依赖它。
否则,你可以试试Numba
/Numba-Scipy
的jit(即时编译)。这显着加快了使用 NumPy 和 Scipy 的代码:
http://numba.pydata.org/
然后您可以导入 jit 装饰器,并在您的函数中使用它:
from numba import jit
@jit # or jit(nopython=False) in other scenarios
def disFunc(x,n):
y = np.power(x, n-1)*np.exp(-x)
return y
> ...
确保同时安装 Numba 和 Numba-Scipy!
如果你只是想集成你在这里给出的功能:
请注意,您希望积分的函数实际上等同于 Lower Incomplete Gamma Function. scipy
includes the scipy.special.gammainc
函数,用于逼近下不完全 Gamma 函数,由(完整)Gamma 函数正则化(即:其输出除以 Gamma( n)).因此,我们可以使用这些专用函数更有效地近似积分:
from scipy import special
import time
# ...
start_time = time.time()
y = special.gammainc(n, beta * t)
y *= special.gamma(n) # Reverse the regularisation
time_taken = (time.time() - start_time)
print(time_taken)
print(y)
所需的时间会因 n 的不同值而异,但对于 n = 5.5,此 运行 在我的机器上用时约 0.0005 秒,而下面的方法为 0.3 秒。
如果要集成不存在封闭形式的任意函数:
这里有一个想法,它只是改进了您在数学上使用的方法,而不是使用 JIT 编译。这 运行s 在我的机器上快了 ~10 倍(你的代码对我来说需要 ~2.2 秒到 运行,这需要 ~0.3 秒):
import numpy as np
from scipy import integrate
import time
def disFunc(x, n):
y = np.power(x, n - 1) * np.exp(-x)
return y
def disFunc2(t_prev, t_cur, n, beta):
y = integrate.quad(disFunc, a=beta * t_prev, b=beta * t_cur, args=(n))
return y[0]
def disFunc3(func):
y = np.vectorize(func)
return y
maxCounter = 6000
stepSize = 0.001
n = 5
beta = 25
t = np.cumsum(np.ones(maxCounter) * stepSize) - stepSize
x = disFunc3(disFunc2)
start_time = time.time()
y = x(t[:-1], t[1:], n, beta)
time_taken = time.time() - start_time
print(time_taken)
print(np.cumsum(y))
这个想法使用了积分的性质:a 运行ge [a, b] 上的积分等价于 [a, c] 上的积分加上 [c, b] 上的积分,对于a和b之间的一些c。因此,我们不是每次都计算 (0, b * t) 之间的积分,而是只计算 (b * prev_t, b * t) 之间的积分(其中 prev_t 是我们使用的最后一个 t ),然后 运行 一个累加和。这只会让它更快,因为在较小的 运行ge.
上执行积分所需的近似迭代次数要少得多需要注意的是,这确实跳过了第一个积分(从 0 到 beta * t[0]),因此您可能需要单独计算它并将其添加到数组的前面。