Python numpy.exp()中溢出
我必须为我的项目计算以下数组的指数:Python numpy.exp()中溢出,python,numpy,overflow,exponential,exp,Python,Numpy,Overflow,Exponential,Exp,我必须为我的项目计算以下数组的指数: w = [-1.52820754859, -0.000234000845064, -0.00527938881237, 5797.19232191, -6.64682108484, 18924.7087966, -69.308158911, 1.1158892974, 1.04454511882, 116.795573742] 但由于号码是18924.7087966,我的电话一直占线 目标是避免使用额外的包,如bigfloat(除了“num
w = [-1.52820754859, -0.000234000845064, -0.00527938881237, 5797.19232191, -6.64682108484,
18924.7087966, -69.308158911, 1.1158892974, 1.04454511882, 116.795573742]
但由于号码是18924.7087966,我的电话一直占线
目标是避免使用额外的包,如bigfloat(除了“numpy”)并获得接近的结果(相对误差较小)
1.到目前为止,我已经尝试使用更高的精度(即浮动128):
但我仍然得到“inf”,这是我想要避免的
如果可能的话,你能帮我解决这个问题吗?Numpy有一个名为
logaddexp(x1, x2) == log(exp(x1) + exp(x2))
没有显式计算中间exp()值。这样可以避免溢出。因此,解决方案如下:
def getlogZ_robust(w):
Z = 0
for x in iter_all_observations():
Z = np.logaddexp(Z, np.dot(x,w))
return Z
只有显著扩展或任意精度的软件包才能处理数字上的巨大差异。
w
中最大和最负数的指数相差8000(!)个数量级float
(即双精度)的精度“只有”15位(意思是1+1e-16
在数字上等于1),因此将小数值添加到最大数值的大指数中没有效果。事实上,exp(18924.7087966)
是如此巨大,以至于它占据了总数的主导地位。下面是在mpmath
中执行扩展精度求和的脚本:指数和exp(18924.7087966)
之和的比率基本上是1
w=[-1.52820754859,-0.000234000845064,-0.00527938881237597.19232191,-6.64682108484,
18924.7087966, -69.308158911, 1.1158892974, 1.04454511882, 116.795573742]
u=最小值(w)
v=最大值(w)
导入mpmath
#使用大量的精确性
mpmath.mp.dps=32768
打印('%.5e'%mpmath.log10(mpmath.exp(v)/mpmath.exp(u)))
#exp(w)的最大值和最小值相差8000个数量级
s=w中x的总和([mpmath.exp(mpmath.mpf(x)))
打印(“%.5e%”(mpmath.exp(v)/s))
#最大exp(w)占主导地位,因此exp(w)和exp(max(w))之和的比率约为1
如果最终结果中由于添加项的数量级相差悬殊而导致数字丢失的问题不值得关注,那么也可以通过以下方式对指数和的log
进行数学变换,以避免大数的exp
:
log(sum(exp(w)))
= log(sum(exp(w-wmax)*exp(wmax)))
= wmax + log(sum(exp(w-wmax)))
在python中:
将numpy导入为np
v=np.数组(w)
m=np.最大值(v)
打印(m+np.log(np.sum(np.exp(v-m)))
请注意,
np.log(np.sum(np.exp(v-m))
在数字上为零,因为最大数的指数完全支配这里的和。可以使用SciPy吗?如果是,请查看。如果没有,您可以从stackoverflow获取源代码,或者在这里搜索一点。可能有许多相同方法的实现分散在stackoverflow答案中。我不能使用SciPy,但我检查了logsumexp,发现numpy也有一个类似的函数叫做“logaddexp”,它计算logaddexp(x1,x2)=log(exp(x1)+exp(x2)),而不显式计算中间exp()值。这样可以避免溢出。谢谢你。
def getlogZ_robust(w):
Z = 0
for x in iter_all_observations():
Z = np.logaddexp(Z, np.dot(x,w))
return Z
log(sum(exp(w)))
= log(sum(exp(w-wmax)*exp(wmax)))
= wmax + log(sum(exp(w-wmax)))