【问题标题】:How to return 0 with divide by zero如何除以零返回 0
【发布时间】:2014-10-08 03:13:05
【问题描述】:

我正在尝试在 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
  • 如果你在做 x / np.abs(x): np.sign() 映射 R -> {-1, 0, 1}。

标签: python arrays numpy error-handling divide-by-zero


【解决方案1】:

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

>>> 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]

在这种情况下,它会在任何 'where' b 不等于 0 的地方进行除法计算。当 b 确实等于 0 时,它与您最初在 'out' 参数中给出的任何值保持不变。

【讨论】:

  • 如果a和/或b可能是整数数组,那么它的概念是一样的,你只需要显式设置正确的输出类型:c = np.divide(a, b, out=np.zeros(a.shape, dtype=float), where=b!=0)
  • out=np.zeros_like(a) 很重要,如注释行所述。
  • 如果我使用np.divide(a, b, out=np.zeros_like(a), where=b!=0),我会收到错误Assigning to function call which doesn't return。奇怪的是,我用了两次,错误只弹出一次。
  • 如果有人对哪个最快感兴趣,这种方法比@denis/@Franck Dernoncourt 的回答要快,运行一百万个周期,我得到 8 秒,而他们的得到 11 秒。
  • 在我的情况下,不仅需要“归零”的浮点值精确等于零,而且这些值“接近”为零。所以以下是有用的np.divide(a, b, out=np.zeros_like(a), where=~np.isclose(b,np.zeros_like(b))),您可以根据您的用例设置iscloseatolrtol
【解决方案2】:

尝试分两步进行。先除法,再替换。

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

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

【讨论】:

  • 你应该在np.errstate(divide='ignore'):上下文中执行除法
  • @WarrenWeckesser 公平点。我已经编辑了答案以包含上下文。如果她/他仍想收到通知,divide='warn' 也很有用。
【解决方案3】:

以其他答案为基础,并改进:

代码:

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]

【讨论】:

  • 很好地检查了0/01/0 错误。
  • 我用DStauffman's answer 中给出的示例数组尝试了你的方法,它似乎产生了非常高的数字而不是np.inf,它仍然是最终结果
  • 我不鼓励这种方法。如果ab 包含NaN,您的解决方案会突然给出0。这很容易隐藏代码中的错误,而且绝对出乎意料。
  • 根据最近的numpy manualnan_to_num() 取值来代替正inf和负inf。 numpy.nan_to_num(x, copy=True, nan=0.0, posinf=None, neginf=None) 是签名。
【解决方案4】:

以@Franck Dernoncourt 的回答为基础,修复 -1 / 0 和我在标量上的错误:

def div0( a, b, fill=np.nan ):
    """ a / b, divide by 0 -> `fill`
        div0( [-1, 0, 1], 0, fill=np.nan) -> [nan nan nan]
        div0( 1, 0, fill=np.inf ) -> inf
    """
    with np.errstate(divide='ignore', invalid='ignore'):
        c = np.true_divide( a, b )
    if np.isscalar( c ):
        return c if np.isfinite( c ) \
            else fill
    else:
        c[ ~ np.isfinite( c )] = fill
        return c

【讨论】:

  • 谢谢,我什至没有发现 @Frank Dernoncourt 的代码中的错误。
  • 嗨,我正在尝试进行数组数学运算,我希望 0/0 得到 0,但我也想在计算中忽略 np.NaN。这会为此工作吗?另外,我试图理解。 c[ ~ np.isfinite( c )] = 0 是做什么的?我从来没有在 python 中使用过 ~ 。它是干什么用的?谢谢
  • @user20408、~ 在 numpy 数组中反转 TrueFalseprint ~ np.array([ True, False, False ])c[ ~ np.isfinite( c )] = 0 表示:找到c 有限的位置,用~ 将它们反转为非有限,并将非有限值设置为0。另见stackoverflow.com/search?q=[numpy]+"boolean+indexing"
【解决方案5】:

已弃用(Python 2 解决方案):

单线(引发警告)

np.nan_to_num(array1 / array2)

【讨论】:

  • 除以零(令人困惑,因为它不正确!)在numpy中给出inf,而不是未定义或nan。因此,这会将除以零设置为 a very large number,而不是像人们期望的那样和 OP 要求的 0。你可以通过设置posinf=0来解决这个问题。
  • 啊,是的,这个答案太老了,以至于代码在 Python 2 中(它可以工作)。
【解决方案6】:

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

假设 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的话,这个操作会有所作为。

【讨论】:

  • indZeros = np.where(arrayB = 0) 这一行应该是 indZeros = np.where(arrayB == 0)
【解决方案7】:

您也可以根据inf 替换,前提是数组dtypes 是浮点数,根据this answer

>>> 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.])

【讨论】:

    【解决方案8】:

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

    >>> 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.])
    

    【讨论】:

      猜你喜欢
      • 2014-12-02
      • 1970-01-01
      • 1970-01-01
      • 2012-07-02
      • 1970-01-01
      • 1970-01-01
      • 2013-09-21
      • 1970-01-01
      相关资源
      最近更新 更多