杂项#

IEEE 754 浮点特殊值#

NumPy 中定义的特殊值:nan, inf,

NaN 可以用作一种简易掩码(如果你不关心原始值是什么)

注意:不能使用相等性来测试 NaN。例如:

>>> myarr = np.array([1., 0., np.nan, 3.])
>>> np.nonzero(myarr == np.nan)
(array([], dtype=int64),)
>>> np.nan == np.nan  # is always False! Use special numpy functions instead.
False
>>> myarr[myarr == np.nan] = 0. # doesn't work
>>> myarr
array([  1.,   0.,  nan,   3.])
>>> myarr[np.isnan(myarr)] = 0. # use this instead find
>>> myarr
array([1.,  0.,  0.,  3.])

其他相关的特殊值函数

isinf():    True if value is inf
isfinite(): True if not nan or inf
nan_to_num(): Map nan to 0, inf to max float, -inf to min float

以下函数与常规函数对应,但 NaN 被排除在结果之外

nansum()
nanmax()
nanmin()
nanargmax()
nanargmin()

>>> x = np.arange(10.)
>>> x[3] = np.nan
>>> x.sum()
nan
>>> np.nansum(x)
42.0

NumPy 如何处理数值异常#

默认情况下,对于 invaliddivideoverflow 会触发 'warn',对于 underflow 则会 'ignore'。但这些设置可以更改,并且可以为不同类型的异常单独设置。不同的行为包括:

  • ‘ignore’ : 异常发生时不做任何处理。

  • ‘warn’ : 打印 RuntimeWarning(通过 Python 的 warnings 模块)。

  • ‘raise’ : 抛出 FloatingPointError

  • ‘call’ : 调用使用 seterrcall 函数指定的函数。

  • ‘print’ : 直接向 stdout 打印警告。

  • ‘log’ : 将错误记录到由 seterrcall 指定的 Log 对象中。

这些行为可以针对所有类型的错误或特定错误进行设置

  • all : 适用于所有数值异常

  • invalid : 当生成 NaN 时

  • divide : 除以零(也包括整数!)

  • overflow : 浮点溢出

  • underflow : 浮点下溢

请注意,整数除以零由相同的机制处理。这些行为是按线程设置的。

示例#

>>> oldsettings = np.seterr(all='warn')
>>> np.zeros(5,dtype=np.float32)/0.
Traceback (most recent call last):
...
RuntimeWarning: invalid value encountered in divide
>>> j = np.seterr(under='ignore')
>>> np.array([1.e-100])**10
array([0.])
>>> j = np.seterr(invalid='raise')
>>> np.sqrt(np.array([-1.]))
Traceback (most recent call last):
...
FloatingPointError: invalid value encountered in sqrt
>>> def errorhandler(errstr, errflag):
...      print("saw stupid error!")
>>> np.seterrcall(errorhandler)
>>> j = np.seterr(all='call')
>>> np.zeros(5, dtype=np.int32)/0
saw stupid error!
array([nan, nan, nan, nan, nan])
>>> j = np.seterr(**oldsettings) # restore previous
...                              # error-handling settings

与 C 接口#

仅对各种选择进行概述。关于每种选择如何工作的细节很少。

  1. 裸机,手动封装您自己的 C 代码。

  • 优点

    • 高效

    • 不依赖其他工具

  • 缺点

    • 学习成本高

      • 需要学习 Python C API 基础知识

      • 需要学习 NumPy C API 基础知识

      • 需要学习如何处理引用计数并熟练掌握。

    • 引用计数通常难以正确处理。

      • 处理不当会导致内存泄漏,甚至更糟的是,段错误

  1. Cython

  • 优点

    • 避免学习 C API

    • 无需处理引用计数

    • 可以用伪 Python 编写代码并生成 C 代码

    • 也可以与现有 C 代码接口

    • 应该能使您免受 Python C API 变更的影响

    • 已成为科学 Python 社区事实上的标准

    • 对数组提供快速索引支持

  • 缺点

    • 可以编写非标准形式的代码,这可能会过时

    • 不如手动封装灵活

  1. ctypes

  • 优点

    • Python 标准库的一部分

    • 适用于与现有共享库接口,特别是 Windows DLL

    • 避免 API/引用计数问题

    • 良好的 NumPy 支持:数组在其 ctypes 属性中拥有所有这些

      a.ctypes.data
      a.ctypes.data_as
      a.ctypes.shape
      a.ctypes.shape_as
      a.ctypes.strides
      a.ctypes.strides_as
      
  • 缺点

    • 不能用于编写转换为 C 扩展的代码,只是一种封装工具。

  1. SWIG(自动封装生成器)

  • 优点

    • 存在已久

    • 支持多种脚本语言

    • 支持 C++

    • 适用于封装大型(多函数)现有 C 库

  • 缺点

    • 在 Python 和 C 代码之间生成大量代码

    • 可能导致性能问题,几乎无法优化消除

    • 接口文件可能难以编写

    • 不一定能避免引用计数问题或需要了解 API

  1. Psyco

  • 优点

    • 通过类似 JIT 的优化将纯 Python 代码转换为高效机器代码

    • 优化良好时速度非常快

  • 缺点

    • 仅限于 Intel 平台(Windows?)

    • 对 NumPy 作用不大?

与 Fortran 接口:#

封装 Fortran 代码的明确选择是 f2py

Pyfort 是一种较旧的替代方案,但已不再受支持。Fwrap 是一个较新的项目,曾看起来很有前景,但已不再开发。

与 C++ 接口:#

  1. Cython

  2. CXX

  3. Boost.python

  4. SWIG

  5. SIP(主要用于 PyQT)