有效地计算双积分

时间:2015-05-24 13:32:05

标签: python scipy montecarlo

我使用scipy计算跟随积分:

from scipy.stats import norm
def integrand(y, x):
    # print "y: %s  x: %s" % (y,x)
    return (du(y)*measurment_outcome_belief(x, 3)(y))*fv_belief(item.mean, item.var)(x)
    return dblquad(
        integrand, norm.ppf(0.001, item.mean, item.var), 
        norm.ppf(0.999, item.mean, item.var),
        lambda x: norm.ppf(0.001, x, 3), 
        lambda x: norm.ppf(0.999, x, 3))[0]

我有项目(正态分布)的信念状态和以项目的实际价值为条件的测量。(也是正态分布) 使用此积分i计算信息的值(测量此项目的有用程度)。

计算此积分需要花费大量时间的问题。 是否有更有效的方法来计算它(我不需要100%的精度),如monte carlo整合或类似的东西?

我知道在python中有skmonaco库用于monte carlo积分,但积分的限制必须是数字,不像scipy,内部积分限制,取决于外部(例如从上面

lambda x: norm.ppf(0.001, x, 3)

) 这里如何使用skmonaco计算双积分

>>> from skmonaco import mcquad
>>> mcquad(lambda x_y: x_y[0]*x_y[1], # integrand
...     xl=[0.,0.],xu=[1.,1.], # lower and upper limits of integration
...     npoints=100000 # number of points
...     )

正如您所看到的,内部积分的极限不依赖于外积分。 有人可以推荐库或方法来有效地计算这个积分吗?

2 个答案:

答案 0 :(得分:2)

在scikit-monaco中处理非立方集成卷的最简单方法是重新定义集成函数,使其在集成区域之外返回0(请参阅文档的this部分):

def modified_integrand(xs):
    x, y = xs
    if norm.ppf(0.001, x, 3) < y < norm.ppf(0.999, x, 3):
        return integrand(xs) # the actual integrand
    else:
        return 0.0

正如Ami Tavori所说,如果集成区域的大部分区域为零,这将是非常低效的。为了进行调解,您可以使用MISER或VEGAS算法:这两种算法都可以“学习”积分的形状,以便在感兴趣的区域更有效地分布点。

那就是说,你的整合区域基本上是一个旋转的矩形:

import matplotlib.pyplot as plt
from scipy.stats import norm
import numpy as np

xs = np.linspace(-10, 10)
ys = np.linspace(-10, 10)

# Plot integration domain
# Red regions are in the domain of integration, blue
# regions are outside
plt.contourf(xs, ys, 
     [ [ 1 if norm.ppf(0.001, x, 3) < y < norm.ppf(0.999, x, 3) 
         else 0 for x in xs ] for y in ys ])

Integration domain

在这种情况下,旋转积分坐标会好得多。例如,定义

r = x - y
R = (x + y)/2.0

您的被子是:

def rotated_integrand(rs):
    R, r = rs
    x = R + r/2.0
    y = R - r/2.0
    return integrand(np.array([x,y]))

r中的积分限制现在是常量(-9.27..9.27,在您给出的示例中)。 R上的积分限制仍为(-infinf),因此您需要逐渐增加R的积分区域,直到积分收敛为止。我肯定会建议使用MISER算法(scikit-monaco中的mcmiser),而不是统一采样。

最后,根据您使用的函数的名称判断,看起来您正在进行某种形式的贝叶斯更新。如果是这种情况,您可以考虑使用Markov Chain Monte Carlo的PyMC库,这可能比通用MC集成库更合适。

答案 1 :(得分:1)

蒙特卡洛集成是一个好主意,并不难实现。然而,相对于其他方法,均匀地对点进行采样会收敛,这些方法迭代地进行采样,并且在每个步骤中,基于体积的样本直到该点为止。

检查recursive stratified sampling

适应您的自定义区域(显然不是超立方体)可能不会非常困难。

不幸的是,我认为没有Python库能够开箱即用。