我有一个数字代码,数字可以任意小。我目前正在使用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来复制它。
这很重要,因为我想防止出现奇怪的下溢问题
答案 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。
可能有多种方法可以解决这个问题。
默认情况下,numpy使用64位浮点数。在这种特殊情况下,简单地将输入向量压缩为128位将解决问题,
In [1]: f(x_in.astype('float128'))
Out[1]: array([ 1.0195336e-433, 3.7506545e-434, 1.3797887e-434], dtype=float128)
以一些额外的计算成本为代价。
正确的方法是考虑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.])
最后,在极少数情况下,当我们不能(或不想)重写数学问题时,我们可以使用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数组。对于大型阵列尺寸,这将非常慢。
在任何情况下,您都需要知道代码的哪个部分生成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
。