集成在Python中返回数组的函数

时间:2015-12-18 00:36:57

标签: python numpy scipy

我有很多要整合的数据,并希望找到一种只用矩阵来完成所有操作的方法,并且愿意在准确性方面做出妥协以提高性能。我的想法是这样的:

import numpy
import scipy

a = np.array([1,2,3])

def func(x):
    return x**2 + x

def func2(x):
    global a
    return a*x

def integrand(x):
    return func(x)*func2(x)

integrated = quad(integrand, 0, 1)

所以我试图将每个元素集成到integrand的数组中。

我知道有可能像这样使用numpy.vectorize()

integrated = numpy.vectorize(scipy.integrate.quad)(integrand, 0, 1)

但我无法正常工作。有没有办法在python中执行此操作?

解决方案

现在好了,我学到了更多的python我可以回答这个问题,如果有人碰巧稳定在它上面并且有同样的问题。这样做的方法是编写函数,好像它们将采用标量值,而不是向量作为输入。从上面的代码开始,我们将拥有的是

import numpy as np
import scipy.integrate.quad

a = np.array([1, 2, 3]) # arbitrary array, can be any size

def func(x):
    return x**2 + x

def func2(x, a):
    return a*x

def integrand(x, a):
    return func(x)*func2(x, a)

def integrated(a):
    integrated, tmp = scipy.integrate.quad(integrand, 0, 1, args = (a))
    return integrated

def vectorizeInt():
    global a
    integrateArray = []
    for i in range(len(a)):
        integrate = integrated(a[i])
        integrateArray.append(integrate)
    return integrateArray

并非您要整合的变量必须是函数的第一个输入。这是scipy.integrate.quad所必需的。如果要对方法进行集成,则它是典型self之后的第二个参数(即x中集成了def integrand(self, x, a):)。另外,args = (a)必须告诉quad函数aintegrand的值。如果integrand有很多参数,比如def integrand(x, a, b, c, d):,您只需将参数按顺序放在args中。那就是args = (a, b, c, d)

2 个答案:

答案 0 :(得分:4)

vectorize无法提供有关提高使用quad的代码性能的帮助。要使用quad,您必须为integrate返回的值的每个组成部分单独调用它。

对于矢量化但不太准确的近似值,您可以使用numpy.trapzscipy.integrate.simps

您的函数定义(至少是问题中显示的函数定义)是​​使用全部支持广播的numpy函数实现的,因此在[0,1]上给定x值的网格时,您可以这样做:< / p>

In [270]: x = np.linspace(0.0, 1.0, 9).reshape(-1,1)

In [271]: x
Out[271]: 
array([[ 0.   ],
       [ 0.125],
       [ 0.25 ],
       [ 0.375],
       [ 0.5  ],
       [ 0.625],
       [ 0.75 ],
       [ 0.875],
       [ 1.   ]])

In [272]: integrand(x)
Out[272]: 
array([[ 0.        ,  0.        ,  0.        ],
       [ 0.01757812,  0.03515625,  0.05273438],
       [ 0.078125  ,  0.15625   ,  0.234375  ],
       [ 0.19335938,  0.38671875,  0.58007812],
       [ 0.375     ,  0.75      ,  1.125     ],
       [ 0.63476562,  1.26953125,  1.90429688],
       [ 0.984375  ,  1.96875   ,  2.953125  ],
       [ 1.43554688,  2.87109375,  4.30664062],
       [ 2.        ,  4.        ,  6.        ]])

也就是说,通过使x成为具有形状(n,1)的数组,integrand(x)返回的值具有形状(n, 3)a中的每个值都有一列。

您可以使用numpy.trapz()将该值传递给scipy.integrate.simps()axis=0,以获得积分的三个近似值。你可能想要一个更精细的网格:

In [292]: x = np.linspace(0.0, 1.0, 101).reshape(-1,1)

In [293]: np.trapz(integrand(x), x, axis=0)
Out[293]: array([ 0.583375,  1.16675 ,  1.750125])

In [294]: simps(integrand(x), x, axis=0)
Out[294]: array([ 0.58333333,  1.16666667,  1.75      ])

将其与重复调用quad进行比较:

In [296]: np.array([quad(lambda t: integrand(t)[k], 0, 1)[0] for k in range(len(a))])
Out[296]: array([ 0.58333333,  1.16666667,  1.75      ])

你的函数integrate(我假设只是一个例子)是一个三次多项式,Simpson's rule给出了精确的结果。一般来说,不要期望simps给出这样一个准确的答案。

答案 1 :(得分:0)

quadpy(我的一个项目)是完全矢量化的。使用

安装
pip install quadpy

然后再做

import numpy
import quadpy


def integrand(x):
    return [numpy.sin(x), numpy.exp(x)]  # ,...


res = quadpy.line_segment.integrate(
        integrand,
        [0, 1],
        quadpy.line_segment.GaussLegendre(5)
        )
print(res)

输出:

[ 0.45969769  1.71828183]