numpy.reciprocal重复调用时返回不同的值

3

我有一个numpy数组ssh_sum

>>> ssh_sum
array([[ 0.,  2.,  1.,  0.,  0.,  0.],
       [ 0.,  0.,  1.,  2.,  0.,  0.],
       [ 0.,  0.,  0.,  1.,  0.,  2.]])

我希望在这个数组中计算逐元素的倒数值。当我多次调用np.reciprocal时,Numpy会返回不同的值:
>>> ssh_sum
array([[ 0.,  2.,  1.,  0.,  0.,  0.],
       [ 0.,  0.,  1.,  2.,  0.,  0.],
       [ 0.,  0.,  0.,  1.,  0.,  2.]])
>>> np.reciprocal(ssh_sum, where=(ssh_sum > 0.))
array([[  6.90326535e-310,   5.00000000e-001,   1.00000000e+000,
          0.00000000e+000,   1.07034283e-296,   1.33666925e+241],
       [  4.74783847e-309,   1.45260789e-296,   1.00000000e+000,
          5.00000000e-001,   2.13436228e-287,  -3.13188338e-294],
       [  4.85105226e-309,   1.08690709e+171,   4.09521901e+149,
          1.00000000e+000,   2.82730247e-311,   5.00000000e-001]])
>>> np.reciprocal(ssh_sum, where=(ssh_sum > 0.))
array([[ inf,  0.5,  1. ,  inf,  inf,  inf],
       [ inf,  inf,  1. ,  0.5,  inf,  inf],
       [ inf,  inf,  inf,  1. ,  inf,  0.5]])
>>> np.reciprocal(ssh_sum, where=(ssh_sum > 0.))
array([[  6.90326535e-310,   5.00000000e-001,   1.00000000e+000,
          0.00000000e+000,   1.07034283e-296,   1.33666925e+241],
       [  4.74783847e-309,   1.45260789e-296,   1.00000000e+000,
          5.00000000e-001,   2.13436228e-287,  -3.13188338e-294],
       [  4.85105226e-309,   1.08690709e+171,   4.09521901e+149,
          1.00000000e+000,   2.82730247e-311,   5.00000000e-001]])
>>> np.reciprocal(ssh_sum, where=(ssh_sum > 0.))
array([[ inf,  0.5,  1. ,  inf,  inf,  inf],
       [ inf,  inf,  1. ,  0.5,  inf,  inf],
       [ inf,  inf,  inf,  1. ,  inf,  0.5]])

这里发生了什么事情?我正在使用Python 3.4.5和numpy 1.13.3。


2
如果你需要一个解决方法,总是可以使用以下方法; m = ssh_sum > 0 ; ssh_sum[m] = 1 / ssh_sum[m] - cs95
谢谢 @cᴏʟᴅsᴘᴇᴇᴅ,你的第二条评论解决了问题。 - Hinton
你能升级到1.14吗?如果这是你的numpy版本中的一个错误,或者是你的numpy副本的安装问题,谁知道它是否会影响你所依赖的其他任何东西呢? - abarnert
我刚刚升级到1.14版本,现在调用的行为是一致的,但是它仍然将0值设置为类似于4.85105226e-309这样的垃圾值,而不是保持为零。 - Hinton
也许是我的CPU - Intel(R) Xeon(R) CPU E5-2620 v4 @ 2.10GHz,微码0xb00001b。 - Hinton
4.05e-309非常接近于0——也就是说,使用默认值的np.isclose已经足够接近了。 - abarnert
1个回答

5
这个问题不仅仅出现在reciprocal函数中,任何使用where参数的操作都会出现这个问题。我已经使用numpy的主分支(np.__version__'1.15.0.dev0+c093997')复现了这个问题,例如abs, sign, add, subtract等函数。
如果您仔细阅读numpy“ufuncs”的文档字符串并正确解释它们,您将看到这种行为不是一个错误。以下是numpy.reciprocal文档字符串中相关的描述:
out : ndarray, None, or tuple of ndarray and None, optional
    A location into which the result is stored. If provided, it must have
    a shape that the inputs broadcast to. If not provided or `None`,
    a freshly-allocated array is returned. A tuple (possible only as a
    keyword argument) must have length equal to the number of outputs.
where : array_like, optional
    Values of True indicate to calculate the ufunc at that position, values
    of False indicate to leave the value in the output alone.

请注意以下内容:
  • where表示“值为False表示保留输出中的该值不变。”
  • out表示“如果未提供或为None,则返回新分配的数组。”

由于您没有提供out参数,因此您的调用reciprocal将分配一个新数组。该数组的内容未初始化; 该数组保存了分配内存时存在的任何东西。当您使用where参数时,只会为where为True的输出位置分配值。不会触及where为False的位置,因此它们保存了分配数组时存在的任何随机内容。对于浮点输出,输出中的随机内容可能是0.04.85105226e-309或任何其他随机值。

为了按照您的意图使用where参数,您还应该提供自己的out参数,并将其初始化为您希望在where为False的输出中设置的值。在您的情况下,您应该传入一个零数组:

In [84]: ssh_sum
Out[84]: 
array([[0., 2., 1., 0., 0., 0.],
       [0., 0., 1., 2., 0., 0.],
       [0., 0., 0., 1., 0., 2.]])

In [85]: out = np.zeros_like(ssh_sum)

In [86]: np.reciprocal(ssh_sum, where=ssh_sum > 0.0, out=out)
Out[86]: 
array([[0. , 0.5, 1. , 0. , 0. , 0. ],
       [0. , 0. , 1. , 0.5, 0. , 0. ],
       [0. , 0. , 0. , 1. , 0. , 0.5]])

In [87]: out
Out[87]: 
array([[0. , 0.5, 1. , 0. , 0. , 0. ],
       [0. , 0. , 1. , 0.5, 0. , 0. ],
       [0. , 0. , 0. , 1. , 0. , 0.5]])

太棒了,谢谢。我猜想我无法复制它的原因是因为我的Mac自动分配了一块0的区块。 - cs95

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接