我有一个概率列表,我需要将其标准化为1.0
例如probs = [0.01,0.03,0.005]
我意识到这是通过将每个概率除以probs
的总和来完成的。但是,如果概率变得非常小,Python会告诉我sum(probs)=0.0
。我知道这是一个下溢问题。我想我应该使用每个概率的日志。我该怎么做?
答案 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并进行高精度数学运算。