使用RuntimeWarning进行numpy除法:double_scalars中遇到无效值

时间:2015-01-05 17:15:04

标签: python numpy warnings

我写了以下脚本:

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将它们变为零,但实际上除法有结果。

如何解决这类问题?

2 个答案:

答案 0 :(得分:60)

你无法解决它。只需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* 1089y=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也是安全的。

答案 1 :(得分:13)

你可以使用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.misc.logsumexp

In [52]: from scipy.misc import logsumexp

In [53]: res = np.exp(logsumexp(-3*d) - logsumexp(-3*e))

In [54]: res
Out[54]: 1.1050349147204485e-116