我有以下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 开始返回inf
和nan
。 方法2 也没有为i
的每个元素提供正确的值。但是,它能够计算更多。方法2对i >= 64
失败。
这两种方法几乎在同一时间给出答案(len(i) = 15000
为0.7秒,使用timeit
确定)。我不明白的是不同的结果。这是因为我学会了尽可能避免python中的for loops
。这次似乎并非如此。
它与记忆有关的想法也让我想到了。但是,评估一个元素,即print func(0, 64)
也会返回0.
(等于方法2的输出)。
发生了什么事?
答案 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在发布时不应出现此问题。