Sha*_*utt 5 python integration numpy scipy numerical-integration
我对进行二维数值积分感兴趣。现在我正在使用scipy.integrate.dblquad但它非常慢。请参阅下面的代码。我的需要是用完全不同的参数评估这个积分 100 次。因此我想让处理尽可能快速和高效。代码是:
import numpy as np
from scipy import integrate
from scipy.special import erf
from scipy.special import j0
import time
q = np.linspace(0.03, 1.0, 1000)
start = time.time()
def f(q, z, t):
return t * 0.5 * (erf((t - z) / 3) - 1) * j0(q * t) * (1 / (np.sqrt(2 * np.pi) * 2)) * np.exp(
-0.5 * ((z - 40) / 2) ** 2)
y = np.empty([len(q)])
for n in range(len(q)):
y[n] = integrate.dblquad(lambda t, z: f(q[n], z, t), 0, 50, lambda z: 10, lambda z: 60)[0]
end = time.time()
print(end - start)
Run Code Online (Sandbox Code Playgroud)
所花费的时间是
212.96751403808594
Run Code Online (Sandbox Code Playgroud)
这太多了。请建议一个更好的方法来实现我想做的事情。我来这里之前尝试进行一些搜索,但没有找到任何解决方案。我读过quadpy可以更好更快地完成这项工作,但我不知道如何实现同样的工作。请帮忙。
几乎是你的例子
我只是直接将函数传递给scipy.integrate.dblquad而不是使用 lambda 生成函数的方法。
import numpy as np
from scipy import integrate
from scipy.special import erf
from scipy.special import j0
import time
q = np.linspace(0.03, 1.0, 1000)
start = time.time()
def f(t, z, q):
return t * 0.5 * (erf((t - z) / 3) - 1) * j0(q * t) * (1 / (np.sqrt(2 * np.pi) * 2)) * np.exp(
-0.5 * ((z - 40) / 2) ** 2)
def lower_inner(z):
return 10.
def upper_inner(z):
return 60.
y = np.empty(len(q))
for n in range(len(q)):
y[n] = integrate.dblquad(f, 0, 50, lower_inner, upper_inner,args=(q[n],))[0]
end = time.time()
print(end - start)
#143.73969149589539
Run Code Online (Sandbox Code Playgroud)
这已经快了一点点(143 vs. 151s),但唯一的用途是有一个简单的例子来优化。
使用 Numba 简单地编译函数
要使其运行,您还需要Numba和numba-scipy。numba-scipy 的目的是提供来自scipy.special.
import numpy as np
from scipy import integrate
from scipy.special import erf
from scipy.special import j0
import time
import numba as nb
q = np.linspace(0.03, 1.0, 1000)
start = time.time()
#error_model="numpy" -> Don't check for division by zero
@nb.njit(error_model="numpy",fastmath=True)
def f(t, z, q):
return t * 0.5 * (erf((t - z) / 3) - 1) * j0(q * t) * (1 / (np.sqrt(2 * np.pi) * 2)) * np.exp(
-0.5 * ((z - 40) / 2) ** 2)
def lower_inner(z):
return 10.
def upper_inner(z):
return 60.
y = np.empty(len(q))
for n in range(len(q)):
y[n] = integrate.dblquad(f, 0, 50, lower_inner, upper_inner,args=(q[n],))[0]
end = time.time()
print(end - start)
#8.636585235595703
Run Code Online (Sandbox Code Playgroud)
使用低级可调用
这些scipy.integrate函数还提供了传递 C 回调函数而不是 Python 函数的可能性。这些函数可以用 C、Cython 或 Numba 等语言编写,我在本示例中使用了它们。主要优点是,函数调用时不需要 Python 解释器交互。
@Jacques Gaudin 的一个很好的答案展示了一种简单的方法来做到这一点,包括附加参数。
import numpy as np
from scipy import integrate
from scipy.special import erf
from scipy.special import j0
import time
import numba as nb
from numba import cfunc
from numba.types import intc, CPointer, float64
from scipy import LowLevelCallable
q = np.linspace(0.03, 1.0, 1000)
start = time.time()
def jit_integrand_function(integrand_function):
jitted_function = nb.njit(integrand_function, nopython=True)
#error_model="numpy" -> Don't check for division by zero
@cfunc(float64(intc, CPointer(float64)),error_model="numpy",fastmath=True)
def wrapped(n, xx):
ar = nb.carray(xx, n)
return jitted_function(ar[0], ar[1], ar[2])
return LowLevelCallable(wrapped.ctypes)
@jit_integrand_function
def f(t, z, q):
return t * 0.5 * (erf((t - z) / 3) - 1) * j0(q * t) * (1 / (np.sqrt(2 * np.pi) * 2)) * np.exp(
-0.5 * ((z - 40) / 2) ** 2)
def lower_inner(z):
return 10.
def upper_inner(z):
return 60.
y = np.empty(len(q))
for n in range(len(q)):
y[n] = integrate.dblquad(f, 0, 50, lower_inner, upper_inner,args=(q[n],))[0]
end = time.time()
print(end - start)
#3.2645838260650635
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2322 次 |
| 最近记录: |