防止Numpy产生NaNs

时间:2015-05-21 22:06:14

标签: python numpy

我有一个数字代码,数字可以任意小。我目前正在使用numpy.nan_to_num制作小值0。有没有办法阻止numpy首先使用NaN

例如,考虑这种情况:

import numpy
a = numpy.array([0]) / numpy.array([0.]) 

给出array([ nan])。如果我然后执行numpy.nan_to_num(a),我会得到array([ 0.])。有没有办法绕过手动nan_to_num步骤并让numpy不使用NaN

我想指出在我的代码中,我不会将0除以0.有一些步骤可以生成NaN(想想一个根查找应用程序,其中一个根为0)但是我如果不提供大量代码,就无法创建MCVE来复制它。

这很重要,因为我想防止出现奇怪的下溢问题

1 个答案:

答案 0 :(得分:2)

假设我们有非常简单的Numpy示例,

In [0]: import numpy as np
   ...: 
   ...: x_in = np.arange(1000, 1003, 1.0)
   ...: 
   ...: def f(x):
   ...:     return np.exp(2*x+1)/np.exp(3*x-2)
   ...: f(x_in)
Out[0]: array([ nan,  nan,  nan])

其中函数f执行一些计算并返回输入向量x_in的NaN。

可能有多种方法可以解决这个问题。

  1. 默认情况下,numpy使用64位浮点数。在这种特殊情况下,简单地将输入向量压缩为128位将解决问题,

    In [1]: f(x_in.astype('float128'))
    Out[1]: array([ 1.0195336e-433,  3.7506545e-434,  1.3797887e-434], dtype=float128)
    

    以一些额外的计算成本为代价。

  2. 正确的方法是考虑NaN出现的原因,并重写函数以避免使用64位浮点数,

    In [2]: def f(x):
       ...:     # using the fact that exp(a)/exp(b) = exp(a-b)                  
       ...:     return np.exp((2*x-1) - (3*x-2))  
       ...: f(x_in)
       ...: 
    Out[2]: array([ 0.,  0.,  0.])
    
  3. 最后,在极少数情况下,当我们不能(或不想)重写数学问题时,我们可以使用mpmath的任意精度浮点数,

    In [3]: import mpmath as mp
       ...: 
       ...: def f(x):
       ...:     mpexp_vect = np.frompyfunc(mp.exp, 1, 1)
       ...:     res = mpexp_vect(2*x+1)/mpexp_vect(3*x-2)
       ...:     return res
       ...: f(x_in)
       ...: 
    Out[3]: array([mpf('1.0195335985731257e-433'), mpf('3.7506545049859113e-434'), 
            mpf('1.3797886833213697e-434')], dtype=object)
    

    结果可以转换为res.astype('float64')的常规numpy数组。对于大型阵列尺寸,这将非常慢。

  4. 在任何情况下,您都需要知道代码的哪个部分生成NaN,以便对其执行某些操作。

    BTW,使用numpy.nan_to_num替换NaN和0.0从根本上是错误的,除非您确切知道为什么会发生这些NaN。因为NaN可以是任何数字,并且它不必是0.例如,     np.exp(-1000 + 1)/np.exp(-1000-1)将导致具有64位浮点数的NaN,而正确答案为np.exp(2) = 7.389