具有极小值的函数的积分对数的数值稳定评估

时间:2017-11-29 21:54:06

标签: python scipy statistics numerical-integration numerical-stability

如果我有一个被定义为sum of two other random numbersZX的随机数Y,那么Z的概率分布就是卷积XY的概率分布。卷积基本上是分布函数的积分。通常对卷积中的积分没有解析解,因此必须使用基本的正交算法进行计算。在伪代码中:

prob_z(z) = integrate(lambda t: prob_x(t) * prob_y(z-t), -inf, inf)

对于一个具体示例,可以使用以下Python / Scipy代码计算正态分布变量Z和日志正态分布变量X的总和Y

from scipy.integrate import quad
from scipy.stats import norm, lognorm
from scipy import log

prob_x = lambda x: norm.pdf(x, 0, 1)  # N(mu=0, sigma=1)
prob_y = lambda y: lognorm.pdf(y, 0.1, scale=10)  # LogN(mu=log(10), sigma=0.1)
def prob_z(z):
    return quad(lambda t: prob_x(t)*prob_y(z-t), -inf, inf)

现在我想计算对数概率。天真的解决方案很简单:

def log_prob_z(z):
    return log(prob_z(z))

然而,这在数值上是不稳定的。在大约39个标准偏差之后,概率分布在数值上为0.0,因此即使对数概率具有某个有限值,也不能通过简单地取概率的对数来在此之外计算。比较norm.pdf(39, 1, 0),其为0.0到norm.logpdf(39, 1, 0),大约为-761。很明显,Scipy不会将logpdf计算为log(pdf) - 它会找到其他方式 - 因为否则会返回-inf,这是一种较差的回复。同样,我想找到解决问题的另一种方法。

(你可能想知道为什么我关心的是从平均值到目前为止的值的对数值。答案是参数拟合。当对数似然是一个非常负的数字时,拟合算法可以更接近,但是当它没有什么可以做的时候是-infnan。)

问题是:有没有人知道如何重新排列log(quad(...))以便我不计算quad(...),从而避免在日志中创建0.0?

1 个答案:

答案 0 :(得分:3)

问题在于,您正在积分的函数的值太小而无法以双精度表示,这仅在1e-308左右才有效。

救援

当双精度不足以进行数值计算时,需要mpmath,用于任意精度浮点运算的库。它有自己的quad例程,但是你需要实现你的pdf函数,以便它们在mpmath级别工作(否则将无法集成任何内容)。有many built-in functions,包括normal pdf,所以我将使用它来说明。

在这里,我使用SciPy将距离为70的两个普通pdf进行卷积:

z = 70
p = quad(lambda t: norm.pdf(t, 0, 1)*norm.pdf(z-t, 0, 1), -np.inf, np.inf)[0]

可悲的是,p恰好是0.0。

import mpmath as mp之后,我在mpmath做同样的事情:

z = 70
p = mp.quad(lambda t: mp.npdf(t, 0, 1)*mp.npdf(z-t, 0, 1), [-mp.inf, mp.inf])

现在p是一个mpmath对象,打印为2.95304756048889e-543,远远超出双精度比例。它的对数mp.log(p)是-1249.22086778731。

基于SciPy的替代方案:对数偏移

如果由于某种原因你不能使用mpmath,你至少可以尝试通过将其值移动到双精度范围来“规范化”该函数。这是一个例子:

z = 70
offset = 2*norm.logpdf(z/2, 0, 1)
logp = offset + np.log(quad(lambda t: np.exp(norm.logpdf(t, 0, 1) + norm.logpdf(z-t, 0, 1) - offset), -np.inf, np.inf)[0])

这里logp打印-1264.66566393,这不如mpmath结果好(所以我们丢失了一些功能),但这是合理的。我做的是:

  • 计算函数对数最大值的对数(这是变量偏移量)
  • 从pdf的对数中减去此偏移量;这是norm.logpdf(t, 0, 1) + norm.logpdf(z-t, 0, 1) - offset
  • 部分
  • 对结果进行取幂,因为我们不能只将对数放在整数中。在代数上,这与pdfs乘以exp(-offset)的乘积相同。但在数字上,这是一个不太可能溢出的数字;实际上,在t = z / 2时,它是exp(0)= 1。
  • 正常整合;取对数,向对数添加偏移量。在代数上,结果只是我们想要的积分的对数。