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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 02:15:49  来源:igfitidea点击:

numpy division with RuntimeWarning: invalid value encountered in double_scalars

pythonnumpywarnings

提问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 answer1is the exponential of 2 very large, negative numbers, so that the result is rounded to zero.

发生这种情况是因为answer1是 2 个非常大的负数的指数,因此结果四舍五入为零。

nanis 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/numpyfunction 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* 1089and y=3* 1093. Now, the argument of this exponential is

上面x=3* 1089y=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 1089in the numerator and the first number 1000at 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