我想通过以下方式在python中执行数学集成:
[1]在scipy.optimize.fsolve的帮助下求解隐式方程以找到被积函数的最大位置
[2]在scipy.integrate.quad的帮助下,将被积函数的最大值移到零并从-10到10进行积分
由于被积函数有一个自由参数xi,我想在numpy的帮助下用一系列xi值执行此操作,所以我使用numpy.vectorize。
现在有两种方法可以对这种算法进行矢量化:
[A]分别向量化[1]和[2]并将vec_ [1]的结果作为输入给出vec_ [2]
[B]矢量化一次执行[1]和[2]的函数
我注意到[A]比[B]快得多。这是代码:
from scipy import optimize, integrate
import numpy as np
from math import exp, sqrt, pi
import time
def integral_with_fsolve(xi):
xc = optimize.fsolve(lambda x: x+1./(1+exp(-x))-xi,0.)
def integrand(x,xi):
return exp(-(x-xi+xc)**2)/(2.*sqrt(2.*pi))/(1.+exp(x+xc))
integral = integrate.quad(integrand,-10.,10.,args=(xi,),epsabs=0.)
return integral[0]
def integral(xi,xc):
def integrand(x,xi):
return exp(-(x-xi+xc)**2)/(2.*sqrt(2.*pi))/(1.+exp(x+xc))
integral = integrate.quad(integrand,-10.,10.,args=(xi,),epsabs=0.)
return integral[0]
def fsolve(xi):
return optimize.fsolve(lambda x: x+1./(1+exp(-x))-xi,0.)
vec_integral_with_fsolve = np.vectorize(integral_with_fsolve)
vec_integral = np.vectorize(integral)
vec_fsolve = np.vectorize(fsolve)
xi = np.linspace(0.,2.,1000)
t0=time.time()
something = vec_integral_with_fsolve(xi)
dur=(time.time()-t0)
speed = xi.size/dur
print('Integrate and fsolve vectorized in one: speed = {} ints/sec'.format(speed))
t0=time.time()
xc = vec_fsolve(xi)
something = vec_integral(xi,xc)
dur=(time.time()-t0)
speed = xi.size/dur
print('Integrate and fsolve vectorized seperately: speed = {} ints/sec'.format(speed))
并且输出总是类似
将矢量化和fsolve集成为一个:速度= 298.151473998英寸/秒
分别对矢量化积分和fsolve:速度= 2136.75134429英寸/秒
由于这只是我实际问题的简化版本,我需要知道它为什么会这样。有人可以解释一下吗?谢谢!
答案 0 :(得分:0)
总之,当您使用“一次性”方法时,这是xc
变量的问题。它是ndarray
,当math.exp()
中使用x
或xi
(两个浮动)调用时,代码会变慢。如果您以“同时”的方式进行xc=float(xc)
,您将获得与“单独”评估中相同的性能。
下面是关于如何找到它的详细说明。
使用cProfile
可以很容易地看出瓶颈在哪里:
AT ONCE:
ncalls tottime percall cumtime percall filename:lineno(function)
1001 0.002 0.000 2.040 0.002 quadpack.py:135(quad)
1001 0.001 0.000 2.038 0.002 quadpack.py:295(_quad)
1001 0.002 0.000 2.143 0.002 tmp.py:15(integral_with_fsolve)
231231 1.776 0.000 1.925 0.000 tmp.py:17(integrand)
470780 0.118 0.000 0.118 0.000 {math.exp}
1001 0.112 0.000 2.037 0.002 {scipy.integrate._quadpack._qagse}
SEPARATELY:
ncalls tottime percall cumtime percall filename:lineno(function)
1001 0.001 0.000 0.340 0.000 quadpack.py:135(quad)
1001 0.001 0.000 0.339 0.000 quadpack.py:295(_quad)
1001 0.001 0.000 0.341 0.000 tmp.py:9(integral)
231231 0.200 0.000 0.278 0.000 tmp.py:10(integrand)
470780 0.054 0.000 0.054 0.000 {math.exp}
1001 0.060 0.000 0.338 0.000 {scipy.integrate._quadpack._qagse}
整体时间是:
AT ONCE:
1 loops, best of 3: 1.91 s per loop
SEPARATELY:
1 loops, best of 3: 312 ms per loop
最大的区别在于integrand
,在integral_with_fsolve
中运行的时间要长近7倍。数值积分quad
也是如此。在“单独”方法中,即使math.exp
也快两倍。
它表明每种方法中评估的类型是不同的。事实上,这就是重点。当“立即”运行时,您可以打印type(xc)
以查看它是numpy.ndarray, float64
,而在“单独”方式中它只是float64
。在math.exp()
中总结这些类型似乎不是一个好主意,如下所示:
xa = -0.389760856858
xc = np.array([[-0.389760856858]],dtype='float64')
timeit for i in range(1000000): exp(xc+xa)
#1 loops, best of 3: 1.96 s per loop
timeit for i in range(1000000): exp(xa+xa)
#10 loops, best of 3: 173 ms per loop
在这两种情况下,math.exp()
都会返回float
。使用exp
,来自sqrt
的{{1}}和pi
可以减少差异但会使代码速度变慢,可能是因为这些函数也可能返回numpy
:< / p>
ndarray
在这种情况下,不要转换为AT ONCE:
1 loops, best of 3: 4.46 s per loop
SEPARATELY:
1 loops, best of 3: 2.14 s per loop
似乎是一个好主意。好主意是转换为ndarray
然后,如下所示(只需要“立刻”方法):
float
新时机:
def integral_with_fsolve(xi):
xc = optimize.fsolve(lambda x: x+1./(1+exp(-x))-xi,0.)
xc = float(xc) # <-- SEE HERE
def integrand(x,xi):
return exp(-(x-xi+xc)**2)/(2.*sqrt(2.*pi))/(1.+exp(x+xc))
integral = integrate.quad(integrand,-10.,10.,args=(xi,),epsabs=0.)
return integral[0]