【问题标题】:Numpy, divide by zero: two different results for the same operationNumpy,除以零:同一操作的两个不同结果
【发布时间】:2016-01-07 20:10:29
【问题描述】:

经过一番搜索后,我仍然在 numpy. 我被我马上报告的矛盾惊呆了:

from numpy import *

seterr(all='ignore')    # Trying to avoid ZeroDivisionError, but unsuccessful.

def f(x) :
    return 1./(x-1.)

有了这个,当我执行f(1.),我得到 ZeroDivisionError: float division by zero.

但是,当我定义 z = array( [ 1., 1. ] ) 并执行 f(z),我没有收到任何错误,但是 array([ inf, inf]).

如您所见,两种输出之间存在某种矛盾。 我的第一个问题是为什么。

理想情况下,我希望得到inf 作为f(1.) 的输出,或者至少是nan,但不是错误(因此计算的停止)。 我的第二个问题是如何管理这个。 请注意我使用seterr 失败的尝试。

【问题讨论】:

  • 难道不是在第一种情况下您正在处理一个整数,而在第二种情况下您正在使用一个 numpy 数组?这些是不同的事情,行为会有所不同,具体取决于为每个操作定义的方式。我认为如果你想要一致的输出,你必须为函数提供一致的输入类型,或者至少是在操作下表现相同的类型。

标签: python numpy divide-by-zero


【解决方案1】:

1. 是一个普通的 Python 浮点数,这些会引发异常而不是使用 nan/inf。当您致电f(1.) 时,numpy 不会以任何方式参与。只是做from numpy import *(或调用像seterr 这样的numpy 函数)不会改变普通Python 类型的工作方式;它只会影响对 numpy 对象的操作,并且只有在显式创建它们时才会获得 numpy 对象。

当您显式创建一个 numpy 对象时,如在您的 f(z) 示例中,您涉及到 numpy,它有自己的类型,不同于基本的 Python 类型。值得注意的是,numpy 数字类型确实使用 nan/inf。

据我所知,没有办法让普通的 Python 浮点数开始返回 naninf 而不是引发异常,因此您必须使用 numpy 标量而不是普通的 Python 浮点数(如所述this question) 如果你想同时支持标量和向量操作。

【讨论】:

  • np.divide(1.0,0.0) 返回带有警告的inf。是否可以从numpy 以某种方式导入divide?这首先有意义吗?
  • @AndrasDeak:您收到警告是因为您仍在传递普通的 Python 浮点数。如果您这样做,例如np.divide(np.float64(1.0), 0),那么您将不会收到警告。如果你希望一切都在 numpy 中发生,你需要你的对象是 numpy 类型,然后再开始对它们进行 numpy 数学运算。 (或者你可以忍受警告。)
  • @AndrasDeak:是的,您可以从 numpy 导入 divide,但这不会改变 / 运算符在普通 Python 浮点数上的工作方式。任何 numpy 都无法使普通的 1.0/0.0 工作方式不同。
  • 感谢您的澄清:)
【解决方案2】:

Numpy 不参与你的函数f。如果你想改变输出,你必须抓住ZeroDivisionError

import numpy

def f(x) :
    try:
        return 1./(x-1.)
    except ZeroDivisionError:
        return numpy.nan

或者使用numpy的除法:

import numpy

def f(x) :
    return numpy.divide(1., (x-1.))

或者只将 numpy 类型传递给f

import numpy

def f(x) :
    return 1./(x-1.)

x = numpy.float_(1)
print f(x) # prints inf

【讨论】:

  • 效果很好,谢谢。但是想象一下,我的脚本中有很多函数,并且我希望每个函数都具有这样的行为,而无需将您建议的代码附加到每个函数中。不知道有没有可能?
  • 是的!但是你应该做的是使用 numpy.divide()。这将默认为您提供inf。更新了我的答案。
  • 我发现你的最后一个建议特别有用,因为有了它,我不必更改我原来的函数 f(x) 中的任何内容(在我正在处理的脚本中,我有很多复杂的函数,我不想用numpy.divide 改变那里的每一个斜线)。我的意思是f可以很容易地重新定义以计算f(numpy.float_(x)),这样就可以了。非常感谢您的编辑!
【解决方案3】:

看起来seterr 打算与 Numpy 类型一起使用;它如何与 Python 本机类型一起使用。另一方面,如果你这样做:

f(np.array((1,)))

您的seterr 不会出现错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-11
    • 1970-01-01
    • 2021-12-18
    • 1970-01-01
    • 2020-02-17
    • 1970-01-01
    • 2016-12-20
    • 2016-07-05
    相关资源
    最近更新 更多