【问题标题】:Perform a double integral over array对数组执行双积分
【发布时间】:2018-11-15 12:49:59
【问题描述】:

我正在对数组执行一维积分,如herehere 所述。正如这些答案中所述,我不能使用 scipy.integrate.quad 对数组上的积分进行矢量化,因为它采用 adaptive 算法,这就是我在下面使用 numpy.trapz 的原因(我也可以使用 @ 987654327@或scipy.integrate.romb)

import numpy as np

# Define some random data
Ndata = 500
data1 = np.random.uniform(.1, .8, Ndata)
data2 = np.random.uniform(.01, .2, Ndata)

# 1D function to integrate
def distFunc(x, c1=1., c2=.1):
    B1 = ((data1 - (1. / x)) / data2)**2
    B2 = ((x - c1) / c2)**2
    f = np.exp(-.5 * B1) * np.exp(-.5 * B2) / c2
    return f

# Values in x to evaluate the integral.
x = np.linspace(.1, 10, 100).reshape(-1, 1)

# Integral in x for each of the Ndata values defined above.
int_exp = np.trapz(distFunc(x), x, axis=0)

这适用于单维,但现在我想执行双积分,用变量替换 c2 常量:

# 2D function to integrate
def distFunc(x, y, c1=1.):
    B1 = ((data1 - (1. / x)) / data2)**2
    B2 = ((x - c1) / y)**2
    f = np.exp(-.5 * B1) * np.exp(-.5 * B2) / y
    return f

据我所知,唯一可用的函数是 scipy.integrate.dblquad bu,这意味着我不能再一次将积分应用于整个数组,我必须使用 for 循环,这相当可观慢一点。

有什么解决办法吗?只要性能合理,我几乎对任何事情都持开放态度(我正在将此双积分插入 MCMC,并且需要对其进行数百万次评估)


添加

这是我在for 循环内使用scipy.integrate.quad 进行一维积分的尝试(即:一次在数组中的一个数据值)。该过程比在整个阵列上使用 np.trapz 慢 50 倍以上。

import numpy as np
from scipy.integrate import quad

# Define some random data
Ndata = 500
data1 = np.random.uniform(.1, .8, Ndata)
data2 = np.random.uniform(.01, .2, Ndata)

# Function to integrate
def distFunc2(x, data1_i, data2_i, c1=1., c2=.1):
    B1 = ((data1_i - (1. / x)) / data2_i)**2
    B2 = ((x - c1) / c2)**2
    f = np.exp(-.5 * B1) * np.exp(-.5 * B2) / c2
    return f

s = t.time()
int_exp = np.zeros(Ndata)
for i in range(Ndata):
    int_exp[i] = quad(distFunc2, .1, 10., args=(data1[i], data2[i]))[0]
print(t.time() - s)

添加 2 个

测试下面给出的答案,它有点工作,但需要注意的是,与dblquad(慢得多但更精确)相比,它有时会失败得非常严重。我猜这与np.trapz使用的算法有关。

# Define some random data
Ndata = 10
data1 = np.random.uniform(.1, 10., Ndata)
data2 = np.random.uniform(.1, .2, Ndata)

c1 = .1
print(integ_dblquad(c1, data1, data2))
print(integ_trapz(c1, data1, data2))

def integ_dblquad(c1, data1, data2):
    def distFunc(y, x, d1_i, d2_i, c1):
        B1 = ((d1_i - (1. / x)) / d2_i)**2
        B2 = ((x - c1) / y)**2
        return (np.exp(-.5 * B1) / d2_i) * np.exp(-.5 * B2) / y

    int_exp = np.zeros(data1.size)
    for i in range(data1.size):
        int_exp[i] = dblquad(
            distFunc, .1, 10., lambda x: 0, lambda x: 5.,
            args=(data1[i], data2[i], c1))[0]

    return np.sum(np.log(int_exp))

def integ_trapz(c1, data1, data2):
    def distFunc2d(x, y):
        B1 = ((data1 - (1. / x)) / data2)**2
        B2 = ((x - c1) / y)**2
        return (np.exp(-.5 * B1) / data2) * np.exp(-.5 * B2) / y

    # Values in x to evaluate the integral.
    x = np.linspace(.1, 10, 1000)
    y = np.linspace(.1, 5., 1000)
    # Integral in x for each of the Ndata values defined above.
    int_exp2d = np.trapz(np.trapz(distFunc2d(x[:, np.newaxis], y[:, np.newaxis, np.newaxis]), y, axis=0), x, axis=0)

    return np.sum(np.log(int_exp2d))

【问题讨论】:

  • 你确定for循环会太慢吗?计算时间应由内部集成例程控制。
  • @meowgoesthedog 请查看我编辑的答案。即使在 for 循环中使用 quad 进行一维积分,也比在整个数组上使用 np.trapz 慢 50 倍以上。
  • 我的意思是在循环中使用np.trapz
  • 但是np.trapz 不能执行双积分(除非我遗漏了什么)。
  • 哦等等,你的意思是使用for 循环和np.trapz 来执行双重积分。我去看看。

标签: python numpy scipy integral


【解决方案1】:

如果我正确理解了您的问题,您可以拨打trapz 两次:

import numpy as np

# Define some random data
Ndata = 500
data1 = np.random.uniform(.1, .8, Ndata)
data2 = np.random.uniform(.01, .2, Ndata)

# 1D function to integrate
def distFunc(x, c1=1., c2=.1):
    B1 = ((data1 - (1. / x)) / data2)**2
    B2 = ((x - c1) / c2)**2
    f = np.exp(-.5 * B1) * np.exp(-.5 * B2) / c2
    return f

def distFunc2d(x, y, c1=1.):
    B1 = ((data1 - (1. / x)) / data2)**2
    B2 = ((x - c1) / y)**2
    f = np.exp(-.5 * B1) * np.exp(-.5 * B2) / y
    return f

# Values in x to evaluate the integral.
x = np.linspace(.1, 10, 100)
y = np.linspace(.1, 10, 100)

# Integral in x for each of the Ndata values defined above.
int_exp = np.trapz(distFunc(x[:,np.newaxis]), x, axis=0)
int_exp2d = np.trapz(np.trapz(distFunc2d(x[:,np.newaxis],y[:,np.newaxis,np.newaxis]), y, axis=0), x, axis=0)

【讨论】:

  • 我已经编辑了我的问题来评论这个答案。它有点有效,只是它有时会惨遭失败。我猜这与np.trapz 有关,与您的实施无关,所以如果没有更好的答案出现,我会接受。谢谢!
  • 没问题。是的,trapz 在幕后只是进行梯形积分,所以你必须以足够精细的尺度评估函数,以使其所做的线性近似是一个很好的。这取决于您通过评估 C 中幕后的所有内容所获得的加速是否弥补了在细粒度范围内评估它所需的额外函数调用的开销的问题。如果你真的需要加快速度,当然可以用 C 重写它。GSL 库具有执行 CQUAD 双自适应集成的功能。
  • 谢谢。我实际上发现我可以将y 中的积分作为伽马函数求解,所以我回到了一个与trapz 一起运行良好的单个积分。
猜你喜欢
  • 2013-05-08
  • 2018-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-03
相关资源
最近更新 更多