from numpy import *
m = array([[1,0],
[2,3]])
我想计算元素log2(m)
,但仅限于m
不为0的地方。在这些地方,我希望得到0。
我现在正在反对:
RuntimeWarning: divide by zero encountered in log2
尝试1:使用where
res = where(m != 0, log2(m), 0)
计算出正确的结果,但我仍然记录了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)
确保屏蔽零会阻止log2
应用于它们,不是吗?不幸的是:我们仍然得到RuntimeWarning: divide by zero encountered in log2
。
即使矩阵被屏蔽,log2
似乎仍然适用于每个元素。
如何在不获得被零除警告的情况下有效地计算numpy数组的逐元素日志?
seterr
暂时禁用这些警告的记录,但这看起来不是一个干净的解决方案。有什么想法吗?
答案 0 :(得分:22)
我们可以使用蒙面数组:
>>> from numpy import *
>>> m = array([[1,0], [2,3]])
>>> x = ma.log(m)
>>> print x.filled(0)
[[ 0. 0. ]
[ 0.69314718 1.09861229]]
答案 1 :(得分:15)
只需禁用该计算的警告:
from numpy import errstate,isneginf,array
m = array([[1,0],[2,3]])
with errstate(divide='ignore'):
res = log2(m)
然后,如果需要,您可以对-inf
进行后处理:
res[isneginf(res)]=0
编辑:我在这里放了一些关于另一个选项的评论,其中使用了掩码数组,在另一个答案中发布了。您应该选择禁用该错误有两个原因:
1)使用屏蔽数组的效率远远低于错误的暂时禁用,并且您要求效率。
2)禁用特定的“除以零”警告不会禁用计算数字日志的其他问题,即负输入。负输入被捕获为“无效值”警告,您将不得不处理它。
另一方面,使用蒙板阵列会将两个错误捕获为相同,并且会导致您不会注意到输入中的负数。换句话说,输入中的负数被视为零,并且结果将给出零。这不是你问的。
3)作为最后一点和个人观点,禁用警告是非常易读的,很明显代码正在做什么并使其更具可持续性。在这方面,我发现这个解决方案更清洁,然后使用蒙面数组。
答案 2 :(得分:5)
屏蔽数组解决方案和禁用警告的解决方案都很好。对于多样性,这是使用scipy.special.xlogy
的另一个。 np.sign(m)
作为x
参数给出,因此xlogy
在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]])
答案 3 :(得分:4)
另一种选择是使用where
parameter of numpy's ufuncs:
m = np.array([[1., 0], [2, 3]])
res = np.log2(m, out=np.zeros_like(m), where=(m!=0))
不引发RuntimeWarning
,在不计算日志的地方引入零。
答案 4 :(得分:2)
以下
from numpy import *
m=array((-1.0,0.0,2.0))
p=m > 0.0
print 'positive=',p
print m[p]
res=zeros_like(m)
res[p]=log(m[p])
print res
答案 5 :(得分:1)
您可以使用类似-
m = np.clip(m, 1e-12, None)
以避免log(0)错误。这会将下界设置为1e-12
。
答案 6 :(得分:1)
对于包含zeros
或negatives
的数组,我们会得到相应的错误。
y = np.log(x)
# RuntimeWarning: divide by zero encountered in log
# RuntimeWarning: invalid value encountered in log
markroxor建议np.clip
,在我的示例中,这将创建一个水平地板。 gg349和其他人使用np.errstate
和np.seterr
,我认为它们比较笨拙,不能解决问题。注意,np.complex
不适用于零。 user3315095使用索引p=0<x
,NumPy.log内置了where
/ out
此功能。 mdeff证明了这一点,但是用-inf
代替了0
,这对我来说是不够的,并且不能解决负面问题。
我建议使用0<x
和np.nan
(或在需要时使用np.NINF
/ -np.inf
)。
y = np.log(x, where=0<x, out=np.nan*x)
John Zwinck使用掩码矩阵np.ma.log
可以工作,但计算速度较慢,请尝试App:timeit。
import numpy as np
x = np.linspace(-10, 10, 300)
# y = np.log(x) # Old
y = np.log(x, where=0<x, out=np.nan*x) # New
import matplotlib.pyplot as plt
plt.plot(x, y)
plt.show()
mask
和where
的时间比较
import numpy as np
import time
def timeit(fun, xs):
t = time.time()
for i in range(len(xs)):
fun(xs[i])
print(time.time() - t)
xs = np.random.randint(-10,+10, (1000,10000))
timeit(lambda x: np.ma.log(x).filled(np.nan), xs)
timeit(lambda x: np.log(x, where=0<x, out=np.nan*x), xs)