Python 带有 RuntimeWarning 的 numpy 除法:在 double_scalars 中遇到无效值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27784528/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
numpy division with RuntimeWarning: invalid value encountered in double_scalars
提问by Heinz
I wrote the following script:
我写了以下脚本:
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
But I got this result and with the error occurred:
但是我得到了这个结果并且出现了错误:
nan
C:\Users\Desktop\test.py:16: RuntimeWarning: invalid value encountered in double_scalars
res = answer.sum()/answer1.sum()
It seems to be that the input element were too small that python turned them to be zeros, but indeed the division has its result.
似乎是输入元素太小,python 将它们变成了零,但实际上除法有它的结果。
How to solve this kind of problem?
如何解决此类问题?
采纳答案by gg349
You can't solve it. Simply answer1.sum()==0
, and you can't perform a division by zero.
你解决不了。简单地说answer1.sum()==0
,您不能执行除以零。
This happens because answer1
is the exponential of 2 very large, negative numbers, so that the result is rounded to zero.
发生这种情况是因为answer1
是 2 个非常大的负数的指数,因此结果四舍五入为零。
nan
is returned in this case because of the division by zero.
nan
由于被零除,在这种情况下返回。
Now to solve your problem you could:
现在要解决您的问题,您可以:
- go for a library for high-precision mathematics, like mpmath. But that's less fun.
- as an alternative to a bigger weapon, do some math manipulation, as detailed below.
- go for a tailored
scipy/numpy
function that does exactly what you want! Check out @Warren Weckesser answer.
- 去寻找一个高精度数学库,比如mpmath。但这不那么有趣。
- 作为更大武器的替代品,请进行一些数学运算,详情如下。
- 去定制一个
scipy/numpy
完全符合你要求的功能吧!查看@Warren Weckesser 的答案。
Here I explain how to do some math manipulation that helps on this problem. We have that for the numerator:
在这里,我将解释如何进行一些有助于解决此问题的数学运算。我们有分子的:
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)))
where above x=3* 1089
and y=3* 1093
. Now, the argument of this exponential is
上面x=3* 1089
和y=3* 1093
. 现在,这个指数的论证是
-x + log(1+exp(-y+x)) = -x + 6.1441934777474324e-06
-x + log(1+exp(-y+x)) = -x + 6.1441934777474324e-06
For the denominator you could proceed similarly but obtain that log(1+exp(-z+k))
is already rounded to 0
, so that the argument of the exponential function at the denominator is simply rounded to -z=-3000
. You then have that your result is
对于分母,您可以类似地进行,但获得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)
which is already extremely close to the result that you would get if you were to keep only the 2 leading terms (i.e. the first number 1089
in the numerator and the first number 1000
at the denominator):
如果您只保留 2 个前导项(即1089
分子中的第一个数字和分母中的第一个数字)1000
,这已经非常接近您得到的结果:
exp(3*(1089-1000))=exp(-267)
For the sake of it, let's see how close we are from the solution of Wolfram alpha (link):
为此,让我们看看我们与 Wolfram alpha ( link)的解决方案有多接近:
Log[(exp[-3*1089]+exp[-3*1093])/([exp[-3*1000]+exp[-3*4443])] -> -266.999993855806522267194565420933791813296828742310997510523
The difference between this number and the exponent above is +1.7053025658242404e-13
, so the approximation we made at the denominator was fine.
这个数字和上面的指数之间的差是+1.7053025658242404e-13
,所以我们在分母上做的近似是好的。
The final result is
最终结果是
'exp(-266.99999385580668) = 1.1050349147204485e-116
From wolfram alpha is (link)
来自 wolfram alpha 是(链接)
1.105034914720621496.. × 10^-116 # Wolfram alpha.
and again, it is safe to use numpy here too.
同样,在这里使用 numpy 也是安全的。
回答by Warren Weckesser
You can use np.logaddexp
(which implements the idea in @gg349's answer):
您可以使用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
Or you can use scipy.special.logsumexp
:
或者你可以使用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