numpy Python对数概率求和代码返回天文数字小[重复]

oknrviil  于 12个月前  发布在  Python
关注(0)|答案(1)|浏览(70)

此问题已在此处有答案

Is floating point math broken?(33答案)
22天前关闭
我有下面的代码:

import numpy as np
def sum_log_prob(l):
    # p = l[-1]
    # i = len(l) - 1
    # while i:
    #     i -= 1
    #     curr_p = l[i]
    #     if p > curr_p:
    #         p = p + np.log1p(np.exp(curr_p - p))
    #     else:
    #         p = curr_p + np.log1p(np.exp(p - curr_p))
    p = float('-inf')
    for x in l:
        if p > x:
            p = p + np.log1p(np.exp(x - p))
        else:
            p = x + np.log1p(np.exp(p - x))
        print(p)
    return p

print(sum_log_prob([np.log(0.2), np.log(0.4), np.log(0.2), np.log(0.2)]))

在理论上,它将取所有概率的总和,所有概率都以对数形式表示。由于对数加法等价于正常乘法,所以我编写了这段代码,以最大限度地减少概率太小时的数值下溢。
问题是,它不起作用。这是循环每次迭代时的p:

-1.6094379124341003
-0.5108256237659906
-0.22314355131420965
1.1102230246251565e-16

正如您所看到的,p非常接近正确答案(0.0,因为log(1)= log(0.2 + 0.4 + 0.2 + 0.2)= 0),但在最后返回一些小数字。
我对这段代码做了两个实现,都给了我同样的错误答案。其中一个在上面的片段中被注解掉了。
请启发,谢谢!

6fe3ivhb

6fe3ivhb1#

您面临的问题可能与数值计算中的舍入和浮点精度有关。当您在浮点表示中处理非常小或非常接近零的数字时,可能会丢失精度。
您可以尝试将np.log1p(np.exp(...))的使用替换为np.log(1 + np.exp(...)),以避免数值问题。此外,在这种情况下,您可以尝试使用NumPy提供的np.logaddexp来更安全地计算。

更新代码如下:

import numpy as np

def sum_log_prob(l):
    p = float('-inf')
    for x in l:
        p = np.logaddexp(p, x)
    return p

print(sum_log_prob([np.log(0.2), np.log(0.4), np.log(0.2), np.log(0.2)]))

这将给予一个数值上更正确的结果。如果您运行这段代码,您应该得到一个接近于零的结果,正如您所期望的那样。

相关问题