【问题标题】:how to call python scipy quad with array inputs如何使用数组输入调用 python scipy quad
【发布时间】:2012-08-07 03:06:39
【问题描述】:

我正在使用嵌套的 scipy.integrate.quad 调用来集成二维被积函数。被积函数由 numpy 函数组成 - 因此将输入数组传递给它比循环输入并为每个输入调用一次要高效得多 - 由于 numpy 的数组,它的速度要快约 2 个数量级。

然而.... numpy 确实可以处理数组输入。有没有其他人看到过这个 - 或者找到了修复它的方法 - 或者我误解了它。我从 quad 得到的错误是:

Traceback (most recent call last):
  File "C:\Users\JP\Documents\Python\TestingQuad\TestingQuad_v2.py", line 159, in <module>
    fnIntegrate_x(0, 1, NCALLS_SET, True)
  File "C:\Users\JP\Documents\Python\TestingQuad\TestingQuad_v2.py", line 35, in fnIntegrate_x
    I = Integrate_x(yarray)
  File "C:\Users\JP\Documents\Python\TestingQuad\TestingQuad_v2.py", line 23, in Integrate_x
    return quad(Integrand, 0, np.pi/2, args=(y))[0]
  File "C:\Python27\lib\site-packages\scipy\integrate\quadpack.py", line 247, in quad
    retval = _quad(func,a,b,args,full_output,epsabs,epsrel,limit,points)
  File "C:\Python27\lib\site-packages\scipy\integrate\quadpack.py", line 312, in _quad
    return _quadpack._qagse(func,a,b,args,full_output,epsabs,epsrel,limit)
quadpack.error: Supplied function does not return a valid float.

我在下面放了一个我正在尝试做的卡通版本 - 我实际上正在做的有一个更复杂的被积函数,但这是 gyst。

肉在顶部 - 底部正在进行基准测试以表明我的观点。

import numpy as np
import time

from scipy.integrate import quad


def Integrand(x, y):
    '''
        Integrand
    '''
    return np.sin(x)*np.sin( y )

def Integrate_x(y):
    '''
        Integrate over x given (y)
    '''
    return quad(Integrand, 0, np.pi/2, args=(y))[0]



def fnIntegrate_x(ystart, yend, nsteps, ArrayInput = False):
    '''

    '''

    yarray = np.arange(ystart,yend, (yend - ystart)/float(nsteps))
    I = np.zeros(nsteps)
    if ArrayInput :
        I = Integrate_x(yarray)
    else :
        for i,y in enumerate(yarray) :

            I[i] = Integrate_x(y)

    return y, I




NCALLS_SET = 1000
NSETS = 10

SETS_t = np.zeros(NSETS)

for i in np.arange(NSETS) :

    XInputs = np.random.rand(NCALLS_SET, 2)

    t0 = time.time()
    for x in XInputs :
        Integrand(x[0], x[1])
    t1 = time.time()
    SETS_t[i] = (t1 - t0)/NCALLS_SET

print "Benchmarking Integrand - Single Values:"
print "NCALLS_SET: ", NCALLS_SET
print "NSETS: ", NSETS    
print "TimePerCall(s): ", np.mean(SETS_t) , np.std(SETS_t)/ np.sqrt(SETS_t.size)        
print "TotalTime: ",np.sum(SETS_t) * NCALLS_SET
'''
Benchmarking Integrand - Single Values:
NCALLS_SET:  1000
NSETS:  10
TimePerCall(s):  1.23999834061e-05 4.06987868647e-06
'''








NCALLS_SET = 1000
NSETS = 10

SETS_t = np.zeros(NSETS)

for i in np.arange(NSETS) :

    XInputs = np.random.rand(NCALLS_SET, 2)

    t0 = time.time()
    Integrand(XInputs[:,0], XInputs[:,1])
    t1 = time.time()
    SETS_t[i] = (t1 - t0)/NCALLS_SET

print "Benchmarking Integrand - Array Values:"
print "NCALLS_SET: ", NCALLS_SET
print "NSETS: ", NSETS    
print "TimePerCall(s): ", np.mean(SETS_t) , np.std(SETS_t)/ np.sqrt(SETS_t.size)        
print "TotalTime: ",np.sum(SETS_t) * NCALLS_SET
'''
Benchmarking Integrand - Array Values:
NCALLS_SET:  1000
NSETS:  10
TimePerCall(s):  2.00009346008e-07 1.26497018465e-07
'''












NCALLS_SET = 1000
NSETS = 100

SETS_t = np.zeros(NSETS)

for i in np.arange(NSETS) :


    t0 = time.time()
    fnIntegrate_x(0, 1, NCALLS_SET, False)
    t1 = time.time()
    SETS_t[i] = (t1 - t0)/NCALLS_SET

print "Benchmarking fnIntegrate_x - Single Values:"
print "NCALLS_SET: ", NCALLS_SET
print "NSETS: ", NSETS    
print "TimePerCall(s): ", np.mean(SETS_t) , np.std(SETS_t)/ np.sqrt(SETS_t.size)        
print "TotalTime: ",np.sum(SETS_t) * NCALLS_SET
'''
NCALLS_SET:  1000
NSETS:  100
TimePerCall(s):  0.000165750000477 8.61204306241e-07
TotalTime:  16.5750000477
'''








NCALLS_SET = 1000
NSETS = 100

SETS_t = np.zeros(NSETS)

for i in np.arange(NSETS) :


    t0 = time.time()
    fnIntegrate_x(0, 1, NCALLS_SET, True)
    t1 = time.time()
    SETS_t[i] = (t1 - t0)/NCALLS_SET

print "Benchmarking fnIntegrate_x - Array Values:"
print "NCALLS_SET: ", NCALLS_SET
print "NSETS: ", NSETS    
print "TimePerCall(s): ", np.mean(SETS_t) , np.std(SETS_t)/ np.sqrt(SETS_t.size)        

'''
****  Doesn't  work!!!! *****
Traceback (most recent call last):
  File "C:\Users\JP\Documents\Python\TestingQuad\TestingQuad_v2.py", line 159, in <module>
    fnIntegrate_x(0, 1, NCALLS_SET, True)
  File "C:\Users\JP\Documents\Python\TestingQuad\TestingQuad_v2.py", line 35, in fnIntegrate_x
    I = Integrate_x(yarray)
  File "C:\Users\JP\Documents\Python\TestingQuad\TestingQuad_v2.py", line 23, in Integrate_x
    return quad(Integrand, 0, np.pi/2, args=(y))[0]
  File "C:\Python27\lib\site-packages\scipy\integrate\quadpack.py", line 247, in quad
    retval = _quad(func,a,b,args,full_output,epsabs,epsrel,limit,points)
  File "C:\Python27\lib\site-packages\scipy\integrate\quadpack.py", line 312, in _quad
    return _quadpack._qagse(func,a,b,args,full_output,epsabs,epsrel,limit)
quadpack.error: Supplied function does not return a valid float.

'''

【问题讨论】:

    标签: python numpy scipy integrate quad


    【解决方案1】:

    可以通过 numpy.vectorize 函数实现。遇到这个问题很久了,才想到这个vectorize函数。

    你可以这样使用它:

    vectorized_function = numpy.vectorize(your_function)
    
    output = vectorized_function(your_array_input)
    

    【讨论】:

    • 酷,会在某个时候尝试这个 - 自从我查看这段代码以来已经有一段时间了 - 但将来可能会有用。
    【解决方案2】:

    恐怕我在这里用否定回答我自己的问题。我不认为这是可能的。似乎quad是用其他东西编写的库的某种端口-因此,内部的库定义了事情的完成方式-因此,如果不重新设计库本身,就不可能做我想做的事情。

    对于其他在多 D 集成方面存在时间问题的人,我发现最好的方法是使用专用的集成库。我发现“古巴”似乎有一些非常有效的多 D 集成例程。

    http://www.feynarts.de/cuba/

    这些例程是用 c 编写的,所以我最终使用 SWIG 与它们交谈 - 最终也为了提高效率,我用 c 重新编写了我的被积函数 - 这加快了加载速度....

    【讨论】:

      【解决方案3】:

      使用quadpy(我的一个项目)。它是完全矢量化的,因此可以处理任何形状的数组值函数,而且速度非常快。

      【讨论】:

      • 谢谢!很高兴知道。很久没有看过这个了 - 但希望对其他人有用。
      【解决方案4】:

      在所有维度上集成从 -np.inf 到 np.inf 的概率密度函数时,我遇到了这个问题。

      我通过创建一个接收 *args 的包装函数、将 args 转换为 numpy 数组并集成包装函数来修复它。

      我认为使用 numpy 的 vectorize 只会整合所有值都相等的子空间。

      这是一个例子:

      from scipy.integrate import nquad
      from scipy.stats import multivariate_normal
      
      mean = [0., 0.]
      cov = np.array([[1., 0.],
                      [0., 1.]])
      
      bivariate_normal = multivariate_normal(mean=mean, cov=cov)
      
      def pdf(*args):
          x = np.array(args)
          return bivariate_normal.pdf(x)
      
      integration_range = [[-18, 18], [-18, 18]]
      
      nquad(pdf, integration_range)
      
      Output: (1.000000000000001, 1.3429066352690133e-08)
      

      【讨论】:

      • 不允许您发表评论是有原因的,它不允许您在“答案”部分在此处发布 cmets。请删除。
      • 我找到了解决他问题的方法,所以我不会删除它。
      猜你喜欢
      • 2014-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多