带有 RuntimeWarning 的 numpy 除法:double_scalars 中遇到无效值
numpy division with RuntimeWarning: invalid value encountered in double_scalars
我写了以下脚本:
import numpy
d = numpy.array([[1089, 1093]])
e = numpy.array([[1000, 4443]])
answer = numpy.exp(-3 * d)
answer1 = numpy.exp(-3 * e)
res = answer.sum()/answer1.sum()
print res
但是我得到了这个结果并且发生了错误:
nan
C:\Users\Desktop\test.py:16: RuntimeWarning: invalid value encountered in double_scalars
res = answer.sum()/answer1.sum()
好像是输入的元素太小了,python变成了零,但除法确实有结果。
如何解决此类问题?
你解决不了。简单地 answer1.sum()==0
,你不能执行除以零。
发生这种情况是因为 answer1
是 2 个非常大的负数的指数,因此结果四舍五入为零。
nan
在这种情况下返回,因为除以零。
现在要解决您的问题,您可以:
- 找一个高精度数学的图书馆,比如 mpmath。但这没那么有趣。
- 作为更大武器的替代品,请进行一些数学运算,详情如下。
- 寻求量身定制的
scipy/numpy
函数,它完全可以满足您的需求!查看@Warren Weckesser 的回答。
在这里,我将解释如何进行一些有助于解决此问题的数学运算。我们有分子:
exp(-x)+exp(-y) = exp(log(exp(-x)+exp(-y)))
= exp(log(exp(-x)*[1+exp(-y+x)]))
= exp(log(exp(-x) + log(1+exp(-y+x)))
= exp(-x + log(1+exp(-y+x)))
高于 x=3* 1089
和 y=3* 1093
。现在,这个指数的自变量是
-x + log(1+exp(-y+x)) = -x + 6.1441934777474324e-06
对于分母,您可以进行类似的处理,但会发现 log(1+exp(-z+k))
已经四舍五入为 0
,因此指数函数在分母处的自变量简单地四舍五入为 -z=-3000
.然后你的结果是
exp(-x + log(1+exp(-y+x)))/exp(-z) = exp(-x+z+log(1+exp(-y+x))
= exp(-266.99999385580668)
这已经非常接近如果您只保留 2 个前导项(即分子中的第一个数字 1089
和第一个数字 1000
在分母):
exp(3*(1089-1000))=exp(-267)
为了它,让我们看看我们离 Wolfram alpha (link) 的解决方案有多近:
Log[(exp[-3*1089]+exp[-3*1093])/([exp[-3*1000]+exp[-3*4443])] -> -266.999993855806522267194565420933791813296828742310997510523
这个数和上面的指数相差+1.7053025658242404e-13
,所以我们在分母处做的近似是好的。
最后的结果是
'exp(-266.99999385580668) = 1.1050349147204485e-116
来自 wolfram alpha 的是 (link)
1.105034914720621496.. × 10^-116 # Wolfram alpha.
再说一次,在这里使用 numpy 也是安全的。
你可以使用np.logaddexp
(它实现了@gg349 的回答中的想法):
In [33]: d = np.array([[1089, 1093]])
In [34]: e = np.array([[1000, 4443]])
In [35]: log_res = np.logaddexp(-3*d[0,0], -3*d[0,1]) - np.logaddexp(-3*e[0,0], -3*e[0,1])
In [36]: log_res
Out[36]: -266.99999385580668
In [37]: res = exp(log_res)
In [38]: res
Out[38]: 1.1050349147204485e-116
或者您可以使用 scipy.special.logsumexp
:
In [52]: from scipy.special import logsumexp
In [53]: res = np.exp(logsumexp(-3*d) - logsumexp(-3*e))
In [54]: res
Out[54]: 1.1050349147204485e-116
我写了以下脚本:
import numpy
d = numpy.array([[1089, 1093]])
e = numpy.array([[1000, 4443]])
answer = numpy.exp(-3 * d)
answer1 = numpy.exp(-3 * e)
res = answer.sum()/answer1.sum()
print res
但是我得到了这个结果并且发生了错误:
nan
C:\Users\Desktop\test.py:16: RuntimeWarning: invalid value encountered in double_scalars
res = answer.sum()/answer1.sum()
好像是输入的元素太小了,python变成了零,但除法确实有结果。
如何解决此类问题?
你解决不了。简单地 answer1.sum()==0
,你不能执行除以零。
发生这种情况是因为 answer1
是 2 个非常大的负数的指数,因此结果四舍五入为零。
nan
在这种情况下返回,因为除以零。
现在要解决您的问题,您可以:
- 找一个高精度数学的图书馆,比如 mpmath。但这没那么有趣。
- 作为更大武器的替代品,请进行一些数学运算,详情如下。
- 寻求量身定制的
scipy/numpy
函数,它完全可以满足您的需求!查看@Warren Weckesser 的回答。
在这里,我将解释如何进行一些有助于解决此问题的数学运算。我们有分子:
exp(-x)+exp(-y) = exp(log(exp(-x)+exp(-y)))
= exp(log(exp(-x)*[1+exp(-y+x)]))
= exp(log(exp(-x) + log(1+exp(-y+x)))
= exp(-x + log(1+exp(-y+x)))
高于 x=3* 1089
和 y=3* 1093
。现在,这个指数的自变量是
-x + log(1+exp(-y+x)) = -x + 6.1441934777474324e-06
对于分母,您可以进行类似的处理,但会发现 log(1+exp(-z+k))
已经四舍五入为 0
,因此指数函数在分母处的自变量简单地四舍五入为 -z=-3000
.然后你的结果是
exp(-x + log(1+exp(-y+x)))/exp(-z) = exp(-x+z+log(1+exp(-y+x))
= exp(-266.99999385580668)
这已经非常接近如果您只保留 2 个前导项(即分子中的第一个数字 1089
和第一个数字 1000
在分母):
exp(3*(1089-1000))=exp(-267)
为了它,让我们看看我们离 Wolfram alpha (link) 的解决方案有多近:
Log[(exp[-3*1089]+exp[-3*1093])/([exp[-3*1000]+exp[-3*4443])] -> -266.999993855806522267194565420933791813296828742310997510523
这个数和上面的指数相差+1.7053025658242404e-13
,所以我们在分母处做的近似是好的。
最后的结果是
'exp(-266.99999385580668) = 1.1050349147204485e-116
来自 wolfram alpha 的是 (link)
1.105034914720621496.. × 10^-116 # Wolfram alpha.
再说一次,在这里使用 numpy 也是安全的。
你可以使用np.logaddexp
(它实现了@gg349 的回答中的想法):
In [33]: d = np.array([[1089, 1093]])
In [34]: e = np.array([[1000, 4443]])
In [35]: log_res = np.logaddexp(-3*d[0,0], -3*d[0,1]) - np.logaddexp(-3*e[0,0], -3*e[0,1])
In [36]: log_res
Out[36]: -266.99999385580668
In [37]: res = exp(log_res)
In [38]: res
Out[38]: 1.1050349147204485e-116
或者您可以使用 scipy.special.logsumexp
:
In [52]: from scipy.special import logsumexp
In [53]: res = np.exp(logsumexp(-3*d) - logsumexp(-3*e))
In [54]: res
Out[54]: 1.1050349147204485e-116