归一化向量在Numpy中产生nan

时间:2015-07-28 19:11:47

标签: python numpy scipy

我从scipy / numpy得到一些奇怪的行为,我怀疑这是一个bug,但有人可能知道更好?我有一对长数组,我打破了长度为2-4的帧用于调试目的。我想标准化每对帧并采用点积。执行此操作的代码(带有一些调试输出)是:

   tf = numpy.copy(t_frame) / norm(t_frame)
   pf = numpy.copy(p_frame) / norm(p_frame)
   print "OPF:"
   print p_frame
   print "PF: "
   print pf
   print "TF norm is: " + str(norm(tf))
   print "PF norm is: " + str(norm(pf))
   print numpy.dot(tf, pf)
   return numpy.dot(tf, pf)

这就是我期待的一段时间(特别是为tf和pf赋予1的标准)但是后来我开始看到这样的行:

  

OPF:

     

[-91 -119 -137 -132]

     

PF:

     

[nan nan nan nan]

什么?这可以在新的Python窗口中正常化:

>>> p = [ -91, -119, -137, -132] 
>>> p / norm(p)
array([-0.37580532, -0.49143773, -0.56577285, -0.54512421])

为了它的价值,我尝试了numpy.linalg.normscipy.linalg.norm,并定义了一个函数来返回点积的平方根。

有什么想法吗?

更新: 谢谢你的建议!我尝试将dtype切换到float128,我很遗憾地得到类似的行为。我实际上倾向于认为它是 Python 中的一个错误,而不是此时的numpy:

  1. 如果这是一个直接的溢出问题,似乎我会在给定列表中得到它。但是如果我在一个新的python会话中这样做,那么规范计算就好了。
  2. 我尝试自己动手:

    def norm(v):
       return (  sum(numpy.array(v)*numpy.array(v)))**(0.5)
    

    这只使用numpy来表示数组。我仍然遇到相同的问题,但在数据集中以后(并且没有运行时警告)。它正在进行大约37000次这些计算。

  3. 我实际上是在两个帧上计算范数,t_frame和p_frame。当且仅当另一个扼流圈的计算有效时才计算一个扼流圈。
  4. 放在一起,我认为在Python(2.7.9)的某些地方有一些奇怪的缓冲区溢出?我最终还需要这些计算速度快;所以我正在考虑转换到Cython进行计算。

    更新2: 我试着自己动手:

    def norm(v):
      sum = float(0)
      for i in range(len(v)):
        sum += v[i]**2
      return sum**(0.5)
    

    问题就消失了。所以我猜它 numpy中的一个bug(Gentoo Linux上的1.9.0)。

2 个答案:

答案 0 :(得分:4)

看起来这是numpy中的一个错误。如果数组的数据类型是np.int16

,我可以重现该问题
In [1]: np.__version__
Out[1]: '1.9.2'

In [2]: x = np.array([ -91, -119, -137, -132], dtype=np.int16)

In [3]: x
Out[3]: array([ -91, -119, -137, -132], dtype=int16)

In [4]: np.linalg.norm(x)
/Users/warren/anaconda/lib/python2.7/site-packages/numpy/linalg/linalg.py:2061: RuntimeWarning: invalid value encountered in sqrt
  return sqrt(sqnorm)
Out[4]: nan

问题也发生在numpy开发版的master分支中。我在这里创建了一个问题:https://github.com/numpy/numpy/issues/6128

如果p_frame实际上是一个16位整数数组,那么简单的解决办法就是:

x = np.asarray(p_frame, dtype=np.float64)
pf = x / norm(x)

答案 1 :(得分:1)

按照Warren的一个链接,我收到了这个警告:

In [1016]: np.linalg.norm(100000*np.ones(2).astype('int16'))
/usr/local/lib/python2.7/site-packages/numpy/linalg/linalg.py:2051: RuntimeWarning: invalid value encountered in sqrt
  return sqrt(add.reduce((x.conj() * x).real, axis=None))

对于这个x2,内部表达式是负数 - 小dtype中溢出的结果。

In [1040]: x2=100000*np.ones(2).astype('int16')
In [1041]: np.add.reduce((x2.conj()*x2).real,axis=None)
Out[1041]: -1474836480

类似于x1

In [1042]: x1
Out[1042]: array([ -9100, -11900, -13700, -13200], dtype=int16)
In [1043]: np.add.reduce((x1.conj()*x1).real,axis=None)
Out[1043]: -66128

如果“点”的总和对于dtype来说太大,则可能是负数,在通过nan时产生sqrt

(我在linux下使用1.8.2和1.9.0)。