我需要按以下方式计算x
(遗留代码):
x = numpy.where(b == 0, a, 1/b)
我认为它适用于python-2.x(就像在python-2.7代码中一样),但它在python-3.x中无效(if b = 0
它会返回错误)。
如何在python-3.x中使其工作?
编辑:错误消息(Python 3.6.3):
ZeroDivisionError: division by zero
答案 0 :(得分:9)
numpy.where
不是条件执行;它是有条件的选择。在函数调用之前总是完全评估Python函数参数,因此函数无法有条件地或部分地评估其参数。
您的代码:
x = numpy.where(b == 0, a, 1/b)
告诉Python反转 b
的每个元素,然后根据a
的元素从1/b
或b == 0
中选择元素。 Python甚至没有达到选择元素的程度,因为计算1/b
失败了。
您只需反转b
的非零部分即可避免此问题。假设a
和b
具有相同的形状,它可能如下所示:
x = numpy.empty_like(b)
mask = (b == 0)
x[mask] = a[mask]
x[~mask] = 1/b[~mask]
答案 1 :(得分:4)
处理数组除法中0个元素的一个老技巧是添加一个条件值:
In [63]: 1/(b+(b==0))
Out[63]: array([1. , 1. , 0.5 , 0.33333333])
(我多年前在apl
)中使用过。
x = numpy.where(b == 0, a, 1/b)
的评估方式与任何其他Python函数的评估方式相同。评估每个函数参数,并将值传递给where
函数。没有'短路'或绕过1/b
的错误值的其他方法。
因此,如果1/b
返回错误,您需要更改b
,以便它不会这样做,在陷阱陷阱ZeroDivisionError
的上下文中计算它,或者跳过1/b
。
In [53]: 1/0
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-53-9e1622b385b6> in <module>()
----> 1 1/0
ZeroDivisionError: division by zero
In [54]: 1.0/0
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-54-99b9b9983fe8> in <module>()
----> 1 1.0/0
ZeroDivisionError: float division by zero
In [55]: 1/np.array(0)
/usr/local/bin/ipython3:1: RuntimeWarning: divide by zero encountered in true_divide
#!/usr/bin/python3
Out[55]: inf
什么是a
和b
?标量,某种规模的数组?
where
(也许b
)是一个数组, a
最有意义:
In [59]: b = np.array([0,1,2,3])
裸师给我一个警告,并inf
元素:
In [60]: 1/b
/usr/local/bin/ipython3:1: RuntimeWarning: divide by zero encountered in true_divide
#!/usr/bin/python3
Out[60]: array([ inf, 1. , 0.5 , 0.33333333])
我可以使用where
将inf
替换为其他内容,例如nan
:
In [61]: np.where(b==0, np.nan, 1/b)
/usr/local/bin/ipython3:1: RuntimeWarning: divide by zero encountered in true_divide
#!/usr/bin/python3
Out[61]: array([ nan, 1. , 0.5 , 0.33333333])
警告可以在@donkopotamus显示时静音。
在seterr
上下文中errstate
的替代with
:
In [64]: with np.errstate(divide='ignore'):
...: x = np.where(b==0, np.nan, 1/b)
...:
In [65]: x
Out[65]: array([ nan, 1. , 0.5 , 0.33333333])
How to suppress the error message when dividing 0 by 0 using np.divide (alongside other floats)?
答案 2 :(得分:1)
如果您希望在除以零时禁用numpy
中的警告,请执行以下操作:
>>> existing = numpy.seterr(divide="ignore")
>>> # now divide by zero in numpy raises no sort of exception
>>> 1 / numpy.zeros( (2, 2) )
array([[ inf, inf],
[ inf, inf]])
>>> numpy.seterr(*existing)
当然,这只能在数组中控制除零。在执行简单的1 / 0
时,它不会阻止错误。
在您的特定情况下,如果我们希望确保我们的工作是b
是标量还是numpy
类型,请执行以下操作:
# ignore division by zero in numpy
existing = numpy.seterr(divide="ignore")
# upcast `1.0` to be a numpy type so that numpy division will always occur
x = numpy.where(b == 0, a, numpy.float64(1.0) / b)
# restore old error settings for numpy
numpy.seterr(*existing)
答案 3 :(得分:0)
我用这个解决了它:
x = (1/(np.where(b == 0, np.nan, b))).fillna(a)
答案 4 :(得分:-2)
这是一个有趣的问题。我的代码在python 3.6 / numpy 1.13.1上进行了测试。
numpy.where
文档声明:
如果给出
x
和y
且输入数组为1-D,则where
为 相当于::[xv if c else yv for (c,xv,yv) in zip(condition,x,y)]
那么为什么你会看到错误?拿这个简单的例子:
c = 0
result = (1 if c==0 else 1/c)
# 1
到目前为止一切顺利。首先检查if c==0
,结果为1
。代码不会尝试评估1/c
。这是因为Python解释器处理 lazy 三元运算符,因此只计算适当的表达式。
现在让我们将其转换为numpy.where
方法:
c = 0
result = (xv if c else yv for (c, xv, yv) in zip([c==0], [1], [1/c]))
# ZeroDivisionError
在应用逻辑之前,在评估zip([c==0], [1], [1/c])
时会发生错误。无法计算生成器表达式本身。作为一个函数,numpy.where
没有,实际上也不能复制Python三元表达式的惰性计算。