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,但这看起来不是一个干净的解决方案.有任何想法吗?
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)作为最后一点和个人观点,禁用警告是非常易读的,很明显代码正在做什么并使其更具可持续性.在这方面,我发现这个解决方案更清洁,然后使用蒙面数组.
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 ,并且在不计算日志的地方引入零。
屏蔽数组解决方案和禁用警告的解决方案都很好.对于多样性,这是另一个使用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)