如何用零除返回0


100

我正在尝试在python中执行元素明智的除法,但是如果遇到零,我需要将商设为零。

例如:

array1 = np.array([0, 1, 2])
array2 = np.array([0, 1, 1])

array1 / array2 # should be np.array([0, 1, 2])

我总是可以在数据中使用for循环,但是要真正利用numpy的优化,我需要除法函数在除以零错误后返回0,而不是忽略错误。

除非我缺少任何东西,否则numpy.seterr()似乎不会在出现错误时返回值。在设置自己的除以零的错误处理方法时,还有人对我如何从numpy中获得最大收益有其他建议吗?


在我的python版本(Python 2.7.11 | Continuum Analytics,Inc.)中,这正是您获得的输出。带有警告。
拉蒙·马丁内斯

最简洁的正确答案是stackoverflow.com/a/37977222/2116338
mrplants

Answers:


181

在numpy v1.7 +中,您可以利用ufuncs的“ where”选项。您可以一行完成事情,而不必与错误上下文管理器打交道。

>>> a = np.array([-1, 0, 1, 2, 3], dtype=float)
>>> b = np.array([ 0, 0, 0, 2, 2], dtype=float)

# If you don't pass `out` the indices where (b == 0) will be uninitialized!
>>> c = np.divide(a, b, out=np.zeros_like(a), where=b!=0)
>>> print(c)
[ 0.   0.   0.   1.   1.5]

在这种情况下,它将在“其中” b不等于零的任何地方进行除法计算。当b等于零时,它与您在'out'参数中最初给它的任何值保持不变。


2
如果aand和/或b可能是整数数组,那么它的概念相同,您只需要显式设置正确的输出类型即可:c = np.divide(a, b, out=np.zeros(a.shape, dtype=float), where=b!=0)
DStauffman

out=np.zeros_like(a)如评论行中所述,这很关键。
乔纳坦·厄斯特罗姆(JonatanÖström)

1
如果使用np.divide(a, b, out=np.zeros_like(a), where=b!=0),则会收到错误消息Assigning to function call which doesn't return。奇怪的是,我使用了两次,错误只弹出一次。
Jelmer Mulder,

45

以@Franck Dernoncourt的答案为基础,修正-1 / 0:

def div0( a, b ):
    """ ignore / 0, div0( [-1, 0, 1], 0 ) -> [0, 0, 0] """
    with np.errstate(divide='ignore', invalid='ignore'):
        c = np.true_divide( a, b )
        c[ ~ np.isfinite( c )] = 0  # -inf inf NaN
    return c

div0( [-1, 0, 1], 0 )
array([0, 0, 0])

谢谢,我什至没有用@Frank Dernoncourt的代码捕获该错误。
hlin117 '16

嗨,我正在尝试做数组数学,我希望0/0得出0,但我也想在计算中忽略np.NaN。这样行吗?另外,我试图理解。c [〜np.isfinite(c)] = 0有什么作用?我从没在Python中使用过〜。这是为了什么 谢谢
user20408 '16

@ user20408,~反转TrueFalse以numpy数组形式存在: print ~ np.array([ True, False, False ])c[ ~ np.isfinite( c )] = 0意思是:找到位置c是有限的位置,使用将它们反转为NOT无限~,并将非限制值设置为0。另请参见stackoverflow.com/search?q=[numpy]+"boolean+indexing
denis

42

以其他答案为基础,并在以下方面进行改进:

码:

import numpy as np

a = np.array([0,0,1,1,2], dtype='float')
b = np.array([0,1,0,1,3], dtype='float')

with np.errstate(divide='ignore', invalid='ignore'):
    c = np.true_divide(a,b)
    c[c == np.inf] = 0
    c = np.nan_to_num(c)

print('c: {0}'.format(c))

输出:

c: [ 0.          0.          0.          1.          0.66666667]

2
很好的检查0/0以及1/0错误。
hlin117

我用DStauffman答案中给出的示例数组尝试了您的方法,它似乎会产生非常高的数字,而不是np.inf,这仍然是最终结果
Gal Avineri

我不鼓励这种方法。如果ab包含NaN,结果就是您的解决方案突然0出现。这很容易隐藏代码中的错误,这绝对是意外的。
DerWeh

根据最近的numpy手册, nan_to_num()采用值来替代正inf和负inf。 numpy.nan_to_num(x, copy=True, nan=0.0, posinf=None, neginf=None)是签名。
Craig Hicks


13

尝试分两个步骤进行。先划分,然后更换。

with numpy.errstate(divide='ignore'):
    result = numerator / denominator
    result[denominator == 0] = 0

numpy.errstate行是可选的,并且仅防止numpy告诉您除零的“错误”,因为您已经打算这样做并处理这种情况。


5
您可能应该在上下文中进行划分np.errstate(divide='ignore'):
Warren Weckesser 2014年

@WarrenWeckesser公平点。我已经编辑了答案以包括上下文。divide='warn'如果他/她仍想得到通知,也可能很有用。
Pi Marillion

2

您也可以inf仅根据数组dtypes为float来基于进行替换,如下所示

>>> a = np.array([1,2,3], dtype='float')
>>> b = np.array([0,1,3], dtype='float')
>>> c = a / b
>>> c
array([ inf,   2.,   1.])
>>> c[c == np.inf] = 0
>>> c
array([ 0.,  2.,  1.])

0

我发现搜索一个相关问题的一个答案是根据分母是否为零来操纵输出。

假设arrayAarrayB已经初始化,但是arrayB有一些零。如果我们要arrayC = arrayA / arrayB安全地进行计算,可以执行以下操作。

在这种情况下,只要我在其中一个单元格中myOwnValue被零除,就将单元格设置为等于,在这种情况下为零

myOwnValue = 0
arrayC = np.zeros(arrayA.shape())
indNonZeros = np.where(arrayB != 0)
indZeros = np.where(arrayB = 0)

# division in two steps: first with nonzero cells, and then zero cells
arrayC[indNonZeros] = arrayA[indNonZeros] / arrayB[indNonZeros]
arrayC[indZeros] = myOwnValue # Look at footnote

脚注:回想起来,这条线无论如何都是不必要的,因为它arrayC[i]被实例化为零。但是,如果是这种情况myOwnValue != 0,该操作将有所作为。


0

另一个值得一提的解决方案:

>>> a = np.array([1,2,3], dtype='float')
>>> b = np.array([0,1,3], dtype='float')
>>> b_inv = np.array([1/i if i!=0 else 0 for i in b])
>>> a*b_inv
array([0., 2., 1.])
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.