【问题标题】:Slow scipy double quadrature integration慢 scipy 双积分
【发布时间】:2014-08-12 07:57:17
【问题描述】:

我正在尝试获取作为集成结果的函数 expected_W 或 H:

地点:

  • theta 是一个包含两个元素的向量:theta_0 和 theta_1
  • f(beta | theta) 是 beta 的正态密度,均值为 theta_0,方差为 theta_1
  • q(epsilon) 是 epsilon 的正态密度,均值为 0,方差为 sigma_epsilon(默认设置为 1)。
  • w(p, theta, eps, beta) 是我作为输入的函数,因此我无法准确预测它的外观。它可能是非线性的,但不是特别讨厌。

这是我实现问题的方式。我确信我制作的包装函数很混乱,所以我也很乐意在这方面获得任何帮助。

from __future__ import division
from scipy import integrate
from scipy.stats import norm
import math
import numpy as np


def exp_w(w_B, sigma_eps = 1, **kwargs):
    '''
    Integrates the w_B function

    Input:
    + w_B : the function to be integrated. 
    + sigma_eps : variance of the epsilon term. Set to 1 by default
    '''

    #The integrand function gives everything under the integral:
    # w(B(p, \theta, \epsilon, \beta)) f(\beta | \theta ) q(\epsilon)
    def integrand(eps, beta, p, theta_0, theta_1, sigma_eps=sigma_eps):
        q_e = norm.pdf(eps, loc=0, scale=math.sqrt(sigma_eps))
        f_beta = norm.pdf(beta, loc=theta_0, scale=math.sqrt(theta_1))

        return w_B(p = p, 
                   theta_0 = theta_0, theta_1 = theta_1,
                   eps = eps, beta=beta)* q_e *f_beta

    #limits of integration. Using limited support for now.
    eps_inf = lambda beta : -10 # otherwise: -np.inf
    eps_sup = lambda beta : 10  # otherwise: np.inf
    beta_inf = -10
    beta_sup = 10

    def integrated_f(p, theta_0, theta_1):
        return integrate.dblquad(integrand, beta_inf, beta_sup,
            eps_inf, eps_sup,
            args = (p, theta_0, theta_1))
    # this integrated_f is the H referenced at the top of the question
    return integrated_f

我用一个简单的 w 函数测试了这个函数,我知道它的解析解(通常情况并非如此)。

def test_exp_w():
    def w_B(p, theta_0, theta_1, eps, beta):
        return 3*(p*eps + p*(theta_0 + theta_1) - beta)

    # Function that I get
    integrated = exp_w(w_B, sigma_eps = 1)

    # Function that I should get
    def exp_result(p, theta_0, theta_1):
        return 3*p*(theta_0 + theta_1) - 3*theta_0

    args = np.random.rand(3)
    d_args = {'p' : args[0], 'theta_0' : args[1], 'theta_1' : args[2]}

    if not (np.allclose(
    integrated(**d_args)[0], exp_result(**d_args)) ):
        raise Exception("Integration procedure isn't working!")    

因此,我的实现似乎正在运行,但就我的目的而言它非常慢。我需要将这个过程重复数万或数十万次(这是价值函数迭代中的一个步骤。如果人们认为它相关,我可以提供更多信息)。

对于scipy 0.14.0 版和numpy 1.8.1 版,计算这个积分需要15 秒。

有人对如何解决这个问题有任何建议吗? 首先, tt 可能有助于获得有界的积分域,但我还没有弄清楚如何做到这一点,或者 SciPy 中的高斯正交是否能很好地处理它(它使用 Gauss-Hermite 吗?) .

感谢您的宝贵时间。

---- 编辑:添加分析时间 -----

%lprun 结果表明大部分时间都花在 _distn_infraestructure.py:1529(pdf)_continuous_distns.py:97(_norm_pdf) 每个都有高达 83244 个电话号码。

【问题讨论】:

  • 您是否考虑过在点网格上评估 H 并在其他任何地方使用插值来定义近似 H?
  • @unutbu:为了清楚起见,您的建议是像我一样使用 dblquad 进行积分,但不要返回函数,而是返回评估点列表?这可能会为我节省很多时间。您对实施有什么建议吗?我必须在 p、theta_0 和 theta_1 上做一个 3D 网格
  • 是的,(假设 H 足够平滑)您可以使用 ndimage.map_coordinates 插值规则间隔的网格,或者,如果您知道需要将您的评估集中在哪里 @ 987654331@,您可以使用interpolate.griddata 对不规则间隔的网格进行插值。
  • @unutbu:你是我翅膀下的风。事实上 p 必须是正数,我对 theta_1 和 theta_0 应该是什么有一些想法,所以我会研究一下。谢谢!
  • @cd98 我也有类似的问题。你用@unutbu suggestion of using interpolate.griddata解决了你的问题吗?如果是,如何?

标签: python numpy scipy


【解决方案1】:

如果函数不是很糟糕的话,集成函数所花费的时间听起来很长。

我建议你做的第一件事是分析时间花在哪里。是花在dblquad 还是其他地方?在集成过程中向w_B 拨打了多少电话?如果时间花在dblquad,调用次数非常多,可以在集成中使用更宽松的容差吗?

似乎高斯乘法实际上使您能够极大地限制积分,因为高斯的大部分能量都在一个非常小的区域内。您可能想尝试计算合理的更严格的界限。您已经将区域限制为 -10..10; -100..100、-10..10 和 -1..1 之间是否有任何显着的性能变化?


如果你知道你的功能比较流畅,那么有米老鼠版的集成:

  • 确定两个轴的合理上限和下限(通过高斯)
  • 计算合理的网格密度(例如,每个方向 100 个点)
  • 计算每个点的 w_B(如果可能需要 w_B 的矢量化版本,这会更快)
  • 总结起来

这是非常低技术但也非常快。它是否为您提供足够好的外部迭代结果是一个有趣的问题。它只是可能。

【讨论】:

  • 感谢您的回答。我从 %prun 添加了一些结果。似乎问题在于它计算正常 pdf 的次数太多,因此可能会降低容差和界限(我会尝试并报告)。我认为对 epsilon 和 beta 进行某种 exp(log) 转换将有助于解决边界问题,但我还没有弄清楚如何去做。
  • 您可能还检查了在 pdf 计算中花费了很多时间(不仅是调用次数)。您可以尝试用自制的版本替换高斯函数(它只有一个 exp,一个平方,一个减法,一个除法,不会花费太多时间)。
猜你喜欢
  • 2018-05-10
  • 2015-08-25
  • 2011-01-23
  • 2023-03-29
  • 2018-11-12
  • 1970-01-01
  • 2016-12-20
  • 1970-01-01
  • 2018-08-12
相关资源
最近更新 更多