在Python中规范化小概率

时间:2014-11-13 18:44:00

标签: python probability

我有一个概率列表,我需要将其标准化为1.0 例如probs = [0.01,0.03,0.005]

我意识到这是通过将每个概率除以probs的总和来完成的。但是,如果概率变得非常小,Python会告诉我sum(probs)=0.0。我知道这是一个下溢问题。我想我应该使用每个概率的日志。我该怎么做?

2 个答案:

答案 0 :(得分:7)

即使非常小的浮点值之和也永远不会为0;它们可能关闭为零,但永远不会完全为零。

将1除以它们的和,并将概率乘以该因子:

def normalize(probs):
    prob_factor = 1 / sum(probs)
    return [prob_factor * p for p in probs]

当然,有些概率可能只占总和的非常小的百分比,并且该百分比可能接近零。但这只是意味着在归一化时,最终可能会得到非常接近零的归一化概率,或者如果小于最小可表示浮点值,则等于零。后者只有在列表中的概率比其他概率小得多的情况下才会发生,以至于它们不再代表任何接近某些事物的概率。

演示:

>>> def normalize(probs):
...     prob_factor = 1 / sum(probs)
...     return [prob_factor * p for p in probs]
... 
>>> normalize([0.0000000001,0.000000000003,0.000000000000005])
[0.9708266589000533, 0.029124799767001597, 4.854133294500266e-05]

极端情况:

>>> import sys
>>> normalize([sys.float_info.max, sys.float_info.min])
[0.9999999999999999, 0.0]
>>> normalize([sys.float_info.max, sys.float_info.min])[-1] == 0
True

答案 1 :(得分:0)

您可以随时使用比例因子来避免手动输入或自动计算的下溢问题,例如:

import math
no_z = ([x for x in probs if x > 0.0])
if len(no_z) == 0:
   print "Unable to calculate with 0.0 as all the probabilities"
order = int(-math.log10(min(no_z)))
if order > 0:
   order = 0
sf = 10**order
scaled = [x * sf for x in probs]
tot = sum(scaled)
norm = [x/tot for x in scaled]

当然,你可能最好只使用bigfloat或numpy并进行高精度数学运算。