使用numpy数组评估函数返回inf和nan

时间:2015-10-17 12:45:21

标签: python arrays for-loop numpy

我有以下numpy数组和函数:

import numpy
import scipy.special

i = numpy.linspace(0, 500, 501, dtype = int)

def func(x, n):
  return scipy.special.eval_hermite(n, x)

我使用两个不同的appraoches评估我的numpy数组i中每个元素的函数:

方法1:

hermites = func(0, i)

方法2:

hermites = [func(0, idx) for idx in i]

这两种方法产生两种不同的答案。它们不同,因为在元素50之后,方法1 开始返回infnan方法2 也没有为i的每个元素提供正确的值。但是,它能够计算更多。方法2对i >= 64失败。

这两种方法几乎在同一时间给出答案(len(i) = 15000为0.7秒,使用timeit确定)。我不明白的是不同的结果。这是因为我学会了尽可能避免python中的for loops。这次似乎并非如此。

它与记忆有关的想法也让我想到了。但是,评估一个元素,即print func(0, 64)也会返回0.(等于方法2的输出)。

发生了什么事?

1 个答案:

答案 0 :(得分:5)

这是由numpy的“ufuncs”偶尔令人惊讶的投射规则创建的scipy中的一个错误。问题是,在scipy版本0.16及更早版本中,当eval_hermite的第一个参数是整数数组而第二个参数是整数标量时,返回值的数据类型是单个精度浮点(numpy.float32)。当第二个参数是64位浮点值时,返回类型为numpy.float64。可以用float32表示的最大值远小于float64,因此当第二个参数是整数时,eval_hermite会更快地溢出到无穷大。

例如,这是scipy 0.16.0和numpy 1.10.1:

In [26]: from scipy.special import eval_hermite

请注意,返回值的数据类型为float32

In [27]: eval_hermite([20, 50, 100, 200], 0)
Out[27]: 
array([  6.70442586e+11,             -inf,              inf,
                    inf], dtype=float32)

如果第二个参数是浮点数,则返回类型为float64,并且可以表示大值:

In [28]: eval_hermite([20, 50, 100, 200], 0.0)
Out[28]: 
array([  6.70442573e+011,  -1.96078147e+039,   3.06851876e+093,
         8.45055019e+216])

代码的解决方法是始终确保eval_hermite的第二个参数是浮点值。例如,

hermites = func(0.0, i)

此问题已在scipy开发版本中修复(请参阅https://github.com/scipy/scipy/pull/4896),因此scipy 0.17在发布时不应出现此问题。