Python 计算二维插值积分时出错。比较numpy阵列
我的优化任务是计算以下积分,并找到Python 计算二维插值积分时出错。比较numpy阵列,python,numpy,scipy,integration,interpolation,Python,Numpy,Scipy,Integration,Interpolation,我的优化任务是计算以下积分,并找到xl和xu的最佳值: 迭代时间太长,所以我决定通过计算所有可能值xl和xu的积分来加速迭代,然后在优化过程中插值计算值 我编写了以下函数: def k_integrand(x, xl, xu): return((x**2)*mpmath.exp(x))/((xu - xl)*(mpmath.exp(x)-1)**2) @np.vectorize def K(xl, xu): y, err = integrate.quad(k_integr
xl
和xu
的最佳值:
迭代时间太长,所以我决定通过计算所有可能值xl
和xu
的积分来加速迭代,然后在优化过程中插值计算值
我编写了以下函数:
def k_integrand(x, xl, xu):
return((x**2)*mpmath.exp(x))/((xu - xl)*(mpmath.exp(x)-1)**2)
@np.vectorize
def K(xl, xu):
y, err = integrate.quad(k_integrand, xl, xu, args = (xl, xu))
return y
以及两个相同的数组grid_xl
和grid_xu
,它们的值以dinamic增量递增
当我运行代码时,我得到以下信息:
K(grid_xl, grid_xu)
Traceback (most recent call last):
File "<ipython-input-2-5b9df02f12b7>", line 1, in <module>
K(grid_xl, grid_xu)
File "C:/Users/909404/OneDrive/Работа/ZnS-FeS/Теплоемкость/Python/CD357/4 - Optimization CD357 interpolation.py", line 75, in K
y, err = integrate.quad(k_integrand, xl, xu, args = (xl, xu))
File "C:\Users\909404\Anaconda3\lib\site-packages\scipy\integrate\quadpack.py", line 323, in quad
points)
File "C:\Users\909404\Anaconda3\lib\site-packages\scipy\integrate\quadpack.py", line 372, in _quad
if (b != Inf and a != -Inf):
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
K(grid\u xl,grid\u xu)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
K(网格xl,网格xu)
文件“C:/Users/909404/OneDrive/Паааааааа/ZnS-FeS/Пааааааааа1072
y、 err=integrate.quad(k_被积函数,xl,xu,args=(xl,xu))
文件“C:\Users\909404\Anaconda3\lib\site packages\scipy\integrate\quadpack.py”,第323行,四行
积分)
文件“C:\Users\909404\Anaconda3\lib\site packages\scipy\integrate\quadpack.py”,第372行,在_quad中
如果(b!=Inf和a!=Inf):
ValueError:包含多个元素的数组的真值不明确。使用a.any()或a.all()
我猜这是因为xl
应该总是小于xu
。
如果xl>=xu
,有没有办法比较xl
和xu
的值并返回NaN
最后,我想要这样的东西:
并且能够使用插值
也许我选错了路?非常感谢您的帮助。除非省略
np.vectorize
decorator,否则我无法重现您的错误。但是,如果将xl
/xu
值设置为一致,则会产生零分错误
无论如何,没有什么可以阻止您在更高级别的函数中检查xu
vsxl
的值。这样,您就可以完全跳过无意义数据点的集成,并尽早返回np.nan
import numpy as np
import mpmath
import scipy.integrate as integrate
def k_integrand(x, xl, xu):
return ((x**2)*mpmath.exp(x))/((xu - xl)*(mpmath.exp(x)-1)**2)
@np.vectorize
def K(xl, xu):
if xu <= xl:
# don't even try to integrate
return np.nan
y, err = integrate.quad(k_integrand, xl, xu, args = (xl, xu))
return y
grid_xl = np.linspace(0.1,1,10) # shape (10,) ~ (1,10)
grid_xu = np.linspace(0.5,4,8)[:,None] # shape (8,1)
您可以看到这些值与链接图像完全一致
现在,我有坏消息和好消息。坏消息是,虽然np.vectorize
为使用数组输入调用标量积分函数提供了语法上的甜头,但与本机for循环相比,它实际上不会给您带来速度提升。好消息是,您可以将对mpmath.exp
的调用替换为对np.exp
的调用,从而更快地得到相同的结果:
def k_integrand_np(x, xl, xu):
return ((x**2)*np.exp(x))/((xu - xl)*(np.exp(x)-1)**2)
@np.vectorize
def K_np(xl, xu):
if xu <= xl:
# don't even try to integrate
return np.nan
y, err = integrate.quad(k_integrand_np, xl, xu, args = (xl, xu))
return y
因此,这两种方法给出了相同的结果(确切地说!),但numpy版本的速度几乎快了15倍。使用低级回调函数进行集成
下面的答案是对@Andras Deak answer的一个评论,但它渴望得到一个评论
scipy积分函数多次调用k_被积函数(np函数),速度相当慢。使用纯Python函数的替代方法是使用。这个函数可以直接用C语言编写,也可以使用像Numba这样的编译器用Python编写。以下是对此的稍微修改版本
示例
import time
import numpy as np
import numba
import scipy.integrate as integrate
from scipy import LowLevelCallable
from numba import cfunc
from numba.types import intc, CPointer, float64
##wrapper for a function that takes 3 input values
def jit_integrand_function(integrand_function):
jitted_function = numba.njit(integrand_function)
@cfunc(float64(intc, CPointer(float64)))
def wrapped(n, xx):
return jitted_function(xx[0], xx[1],xx[2])
return LowLevelCallable(wrapped.ctypes)
#your function to integrate
def k_integrand_np(x, xl, xu):
return ((x**2)*np.exp(x))/((xu - xl)*(np.exp(x)-1)**2)
#compile integrand
k_integrand_nb=jit_integrand_function(k_integrand_np)
#now we can use the low-level callable
@np.vectorize
def K_nb(xl, xu):
if xu <= xl:
# don't even try to integrate
return np.nan
y, err = integrate.quad(k_integrand_nb, xl, xu, args = (xl, xu))
return y
#for comparison
@np.vectorize
def K_np(xl, xu):
if xu <= xl:
# don't even try to integrate
return np.nan
y, err = integrate.quad(k_integrand_np, xl, xu, args = (xl, xu))
return y
#create some data
grid_xl = np.linspace(0.1,1,500)
grid_xu = np.linspace(0.5,4,800)[:,None]
t1=time.time()
res_nb = K_nb(grid_xl, grid_xu)
print(time.time()-t1)
t1=time.time()
res_np = K_np(grid_xl, grid_xu)
print(time.time()-t1)
inds = ~np.isnan(res_nb)
np.allclose(res_nb[inds], res_np[inds])
K_np: 24.58s
K_nb: 0.97s (25x speedup)
allclose: True
在您的案例中,a
和b
是什么?提供完整的错误回溯会很有帮助。我已经添加了完整的错误回溯,希望它能有所帮助。(b!=Inf和a!=-Inf)
不可能在b
和a
为多值数组的情况下进行计算。记下源代码,从第372行开始;根据边界a
和b
是否有限,代码决定使用不同的积分方法。通常,除非显示\u quadpack
例程接受向量参数,否则您的方法将不起作用。第75
和77
行上的参数说明特别指出a
和b
需要是float
s。干得好。我想知道;数组不是完全相等吗?我怀疑这很容易做到,因为numba编译不一定会影响操作顺序,所以两种方法之间的浮点错误可能是相同的。我还想知道这种加速是否足以直接解决OP最初的问题。不,它们并不完全相同。我真的不知道为什么会发生这种情况,但我怀疑Numba将x**2(或np.power(x,2))简化为x*x,这在精度上可能不同,但速度要快得多。关于SIMD的矢量化运算精度可能也会有所不同谢谢,真的很有帮助!通过使用np.sinh()函数重写初始被积函数,并像您建议的那样在K_np中添加“if”语句,我已经设法加快了计算速度。
import time
import numpy as np
import numba
import scipy.integrate as integrate
from scipy import LowLevelCallable
from numba import cfunc
from numba.types import intc, CPointer, float64
##wrapper for a function that takes 3 input values
def jit_integrand_function(integrand_function):
jitted_function = numba.njit(integrand_function)
@cfunc(float64(intc, CPointer(float64)))
def wrapped(n, xx):
return jitted_function(xx[0], xx[1],xx[2])
return LowLevelCallable(wrapped.ctypes)
#your function to integrate
def k_integrand_np(x, xl, xu):
return ((x**2)*np.exp(x))/((xu - xl)*(np.exp(x)-1)**2)
#compile integrand
k_integrand_nb=jit_integrand_function(k_integrand_np)
#now we can use the low-level callable
@np.vectorize
def K_nb(xl, xu):
if xu <= xl:
# don't even try to integrate
return np.nan
y, err = integrate.quad(k_integrand_nb, xl, xu, args = (xl, xu))
return y
#for comparison
@np.vectorize
def K_np(xl, xu):
if xu <= xl:
# don't even try to integrate
return np.nan
y, err = integrate.quad(k_integrand_np, xl, xu, args = (xl, xu))
return y
#create some data
grid_xl = np.linspace(0.1,1,500)
grid_xu = np.linspace(0.5,4,800)[:,None]
t1=time.time()
res_nb = K_nb(grid_xl, grid_xu)
print(time.time()-t1)
t1=time.time()
res_np = K_np(grid_xl, grid_xu)
print(time.time()-t1)
inds = ~np.isnan(res_nb)
np.allclose(res_nb[inds], res_np[inds])
K_np: 24.58s
K_nb: 0.97s (25x speedup)
allclose: True