numpy division with RuntimeWarning:double_scalars中遇到无效值

fcy6dtqo  于 2023-04-21  发布在  Scala
关注(0)|答案(3)|浏览(152)

我写了以下脚本:

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()

但我得到了这个结果,并与错误发生:

nan
C:\Users\Desktop\test.py:16: RuntimeWarning: invalid value encountered in double_scalars
  res = answer.sum()/answer1.sum()

似乎是因为输入元素太小,python把它们变成了零,但是除法确实有它的结果。
如何解决这类问题?

vyu0f0g1

vyu0f0g11#

你不能解决它。简单地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也是安全的。

44u64gxh

44u64gxh2#

你可以使用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
plicqrtu

plicqrtu3#

如果将零长度(在某个维度上)数组传递给使用除法来导出其输出的numpy方法(例如np.mean()np.median()np.varnp.cov等),也会出现此警告。
获取此类数组的常见方法是使用某些条件过滤数组,该条件返回零长度数组。因此,如果即使您不使用非常小或非常大的数字也会引发此警告,请检查数组的形状。
举个例子:

arr = np.array([1, 2, 3])
arr_sliced = arr[arr < 0]   # array([], dtype=int32)
avg = np.mean(arr_sliced)   # RuntimeWarning: invalid value encountered in double_scalars

相关问题