numpy:采取log(矩阵)时有效避免0

nh2*_*nh2 28 numpy

from numpy import *

m = array([[1,0],
           [2,3]])
Run Code Online (Sandbox Code Playgroud)

我想计算元素log2(m),但仅限于m不是0的地方.在那些地方,我希望得到0作为结果.

我现在正在反对:

RuntimeWarning: divide by zero encountered in log2
Run Code Online (Sandbox Code Playgroud)

尝试1:使用 where

res = where(m != 0, log2(m), 0)
Run Code Online (Sandbox Code Playgroud)

这会计算出正确的结果,但我仍然记录了RuntimeWarning: divide by zero encountered in log2.看起来(在语法上它很明显)numpy仍然log2(m)在完整矩阵上进行计算,然后才where选择要保留的值.

我想避免这个警告.


尝试2:使用面具

from numpy import ma

res = ma.filled(log2(ma.masked_equal(m, 0)), 0)
Run Code Online (Sandbox Code Playgroud)

肯定掩盖零会阻止log2它们被应用到它们身上,不是吗?不幸的是:我们仍然得到RuntimeWarning: divide by zero encountered in log2.

即使矩阵被掩盖,log2似乎仍然应用于每个元素.


如何在不获得除零警告的情况下有效地计算numpy数组的逐元素日志?

  • 当然我可以使用暂时禁用这些警告的记录seterr,但这看起来不是一个干净的解决方案.
  • 并确保双的循环将帮助特别处理为0,但是失败numpy的效率.

有任何想法吗?

Joh*_*nck 26

我们可以使用蒙面数组:

>>> from numpy import *
>>> m = array([[1,0], [2,3]])
>>> x = ma.log(m)
>>> print x.filled(0)
[[ 0.          0.        ]
 [ 0.69314718  1.09861229]]
Run Code Online (Sandbox Code Playgroud)


gg3*_*349 15

只需禁用该计算的警告:

from numpy import errstate,isneginf,array

m = array([[1,0],[2,3]])
with errstate(divide='ignore'):
    res = log2(m)
Run Code Online (Sandbox Code Playgroud)

然后你可以-inf根据需要进行后期处理:

res[isneginf(res)]=0
Run Code Online (Sandbox Code Playgroud)

编辑:我在这里放了一些关于另一个选项的评论,它使用了掩码数组,在另一个答案中发布.您应该选择禁用该错误有两个原因:

1)使用屏蔽数组的效率远远低于短暂禁用错误,并且您要求效率.

2)禁用特定的"除以零"警告不会禁用计算数字日志的另一个问题,即负输入.负输入被捕获为"无效值"警告,您将不得不处理它.

另一方面,使用屏蔽数组会将两个错误捕获为相同,并且会导致您在输入中不会注意到负数.换句话说,输入中的负数被视为零,并且结果将给出零.这不是你问的.

3)作为最后一点和个人观点,禁用警告是非常易读的,很明显代码正在做什么并使其更具可持续性.在这方面,我发现这个解决方案更清洁,然后使用蒙面数组.

  • 与`np.errstate(divide ='ignore')一起使用:res = log2(m)`而不是两次调用`seterr`:您不会忘记在计算后禁用忽略,并且此后它也会重置为先前的设置(@ gg349不是atm):<https://docs.scipy.org/doc/numpy/reference/produced/numpy.errstate.html>(是的,我对此很迟:) (2认同)

mde*_*eff 10

另一个选择是使用wherenumpy的ufuncs的参数:

m = np.array([[1., 0], [2, 3]])
res = np.log2(m, out=np.zeros_like(m), where=(m!=0))
Run Code Online (Sandbox Code Playgroud)

RuntimeWarning引发No ,并且在不计算日志的地方引入零。


War*_*ser 5

屏蔽数组解决方案和禁用警告的解决方案都很好.对于多样性,这是另一个使用scipy.special.xlogy. np.sign(m)作为x参数给出,因此xlogy在0 np.sign(m)为0时返回0.结果除以np.log(2)得到基数为2的对数.

In [4]: from scipy.special import xlogy

In [5]: m = np.array([[1, 0], [2, 3]])

In [6]: xlogy(np.sign(m), m) / np.log(2)
Out[6]: 
array([[ 0.       ,  0.       ],
       [ 1.       ,  1.5849625]])
Run Code Online (Sandbox Code Playgroud)