NumPy 1.21.0 Release Notes#

NumPy 1.21.0 版本的主要亮点包括:

  • 持续的 SIMD 工作,涵盖更多函数和平台;

  • 新的 dtype 基础设施和转换的初步工作;

  • Mac 上的 Python 3.8 和 Python 3.9 的 universal2 wheels;

  • 改进的文档;

  • 改进的注解;

  • 用于随机数的新 PCG64DXSM bitgenerator。

此外,还有一如既往的大量错误修复和其他改进。

此版本支持的 Python 版本为 3.7-3.9。Python 3.10 正式发布后将增加官方支持。

警告

使用 gcc-11.1 编译 NumPy 1.20.0 时存在未解决的问题。

  • 优化级别 -O3 在运行测试时会导致许多不正确的警告。

  • 在某些硬件上,NumPY 会挂起在无限循环中。

新增函数#

添加 PCG64DXSM BitGenerator#

在 NumPy 1.17 发布时,PCG64 BitGenerator 在大规模并行环境中的使用被证明存在统计上的弱点,这些弱点在首次发布时并不明显。大多数用户将永远不会遇到这种弱点,并且可以继续安全地使用 PCG64。我们引入了一个新的 PCG64DXSM BitGenerator,它最终将在未来的版本中成为 default_rng 使用的新默认 BitGenerator 实现。PCG64DXSM 解决了统计弱点,同时保留了 PCG64 的性能和特性。

有关更多详细信息,请参阅 使用 PCG64DXSM 升级 PCG64

(gh-18906)

已过期的弃用#

  • unravel_indexshape 参数不再可以作为 dims 关键字参数传递。(已在 NumPy 1.16 中弃用。)

    (gh-17900)

  • 函数 PyUFunc_GenericFunction 已被禁用。它在 NumPy 1.19 中已被弃用。用户应通过 Python API 直接调用 ufunc。

    (gh-18697)

  • 函数 PyUFunc_SetUsesArraysAsData 已被禁用。它在 NumPy 1.19 中已被弃用。

    (gh-18697)

  • PolyBase 已被移除(在 numpy 1.9.0 中已弃用)。请改用抽象类 ABCPolyBase

    (gh-18963)

  • 已移除未使用的 PolyErrorPolyDomainError 异常。

    (gh-18963)

弃用#

`.dtype` 属性必须返回一个 `dtype`#

如果传递到 `np.dtype` 或作为 `dtype=obj` 参数的对象,其 `.dtype` 属性不是 dtype,现在会发出 `DeprecationWarning`。NumPy 将停止尝试递归转换 `.dtype` 的结果。

(gh-13578)

`numpy.convolve` 和 `numpy.correlate` 的不精确匹配已弃用#

`convolve` 和 `correlate` 现在会在函数中为 `mode` 参数找到不区分大小写和/或不精确匹配时发出警告。请为 `mode` 参数传递完整的 `"same"`、`"valid"`、`"full"` 字符串,而不是 `"s"`、`"v"`、`"f"`。

(gh-17492)

`np.typeDict` 已被正式弃用#

`np.typeDict` 是 `np.sctypeDict` 的一个已弃用别名,并且已经存在了超过 14 年(6689502)。现在每次访问 `np.typeDict` 时都会发出弃用警告。

(gh-17586)

在类数组创建期间将引发异常#

当对象在访问特殊属性 `__array__` 或 `__array_interface__` 时引发异常,该异常通常会被忽略。现在当异常不是 AttributeError 时会发出警告。要抑制警告,必须修改引发异常的类型,使其引发 `AttributeError`。

(gh-19001)

四个 `ndarray.ctypes` 方法已被弃用#

`ndarray.ctypes` 对象的四个方法已被弃用,因为它们是其各自属性(未文档化)的实现产物。

相关方法为:

  • `_ctypes.get_data`(使用 `_ctypes.data` 代替)

  • `_ctypes.get_shape`(使用 `_ctypes.shape` 代替)

  • `_ctypes.get_strides`(使用 `_ctypes.strides` 代替)

  • `_ctypes.get_as_parameter`(使用 `_ctypes._as_parameter_` 代替)

(gh-19031)

过期的弃用#

  • `numpy.unravel_index` 的 `shape` 参数不再可以作为 `dims` 关键字参数传递。(已在 NumPy 1.16 中弃用。)

    (gh-17900)

  • 函数 PyUFunc_GenericFunction 已被禁用。它在 NumPy 1.19 中已被弃用。用户应通过 Python API 直接调用 ufunc。

    (gh-18697)

  • 函数 PyUFunc_SetUsesArraysAsData 已被禁用。它在 NumPy 1.19 中已被弃用。

    (gh-18697)

移除弃用的 `PolyBase` 和未使用的 `PolyError` 及 `PolyDomainError`#

PolyBase 已被移除(在 numpy 1.9.0 中已弃用)。请改用抽象类 ABCPolyBase

此外,未使用的 `PolyError` 和 `PolyDomainError` 异常已从 `numpy.polynomial` 中移除。

(gh-18963)

兼容性说明#

通用函数中的错误类型更改#

在某些情况下,通用函数现在可能对无效输入引发不同的错误。主要变化是将 `RuntimeError` 替换为更合适的 `TypeError`。当同一调用中存在多个错误时,NumPy 现在可能引发一个不同的错误。

(gh-15271)

`__array_ufunc__` 参数验证#

NumPy 现在将在调用 `__array_ufunc__` 之前部分验证参数。以前,当已知会发生调度时,可以传递无效参数(例如,不存在的关键字参数)。

(gh-15271)

`__array_ufunc__` 和其他位置参数#

以前,所有通过位置传递的参数都会被检查是否支持 `__array_ufunc__`。对于 `reduce`、`accumulate` 和 `reduceat`,所有参数都可以通过位置传递。这意味着当它们通过位置传递时,以前可以要求它们通过 `__array_ufunc__` 处理 ufunc 调用。由于这取决于参数传递方式(通过位置或通过关键字),NumPy 现在仅根据输入和输出数组进行调度。例如,NumPy 在 `np.add.reduce` 这样的归约中,永远不会根据 `where` 数组进行调度。

(gh-15271)

验证 `Generator.uniform` 中的输入值#

在 `np.random.Generator.uniform` 中检查了 `high - low >= 0`。如果 `low > high`,则引发 `ValueError`。以前,顺序颠倒的输入是可以接受的,并且会被静默交换,因此如果 `low > high`,生成的值为 `high + (low - high) * random()`。

(gh-17921)

从默认包含路径中移除了 `/usr/include`#

使用 `numpy.distutils` 构建包时,默认的包含路径不再包含 `/usr/include`。此路径通常由编译器添加,硬编码可能会有问题。如果这导致问题,请提交一个 issue。PR 18658 中记录了一个解决方法。

(gh-18658)

与 `dtype=...` 的比较更改#

当使用比较 ufuncs(`equal`、`less` 等)的 `dtype=`(或 `signature`)参数时,将来这会表示所需的输出 dtype。这意味着

np.equal(2, 3, dtype=object)

将发出 `FutureWarning`,表示将来会返回一个 `object` 数组,而目前这对于

np.equal(None, None, dtype=object)

由于 `np.array(None)` 已经是 object 数组。(对于某些其他 dtype 也会发生这种情况。)

由于比较通常只返回布尔数组,将来提供任何其他 dtype 都将始终引发错误,而现在则会发出 `DeprecationWarning`。

(gh-18718)

ufuncs 中 `dtype` 和 `signature` 参数的更改#

通用函数参数 `dtype` 和 `signature`(对于归约如 `np.add.reduce`(即 `np.sum` 的实现)也有效)现在将在提供的 `dtype` 不是“基本” dtype 时发出警告。

NumPy 几乎总是忽略这些输入的元数据、字节序或时间单位。NumPy 现在将始终忽略它们,并在字节序或时间单位发生更改时引发错误。以下是会引发错误的最重要示例。在某些情况下,之前存储的信息并未被忽略,在所有这些情况下,现在都会引发错误。

# Previously ignored the byte-order (affect if non-native)
np.add(3, 5, dtype=">i32")

# The biggest impact is for timedelta or datetimes:
arr = np.arange(10, dtype="m8[s]")
# The examples always ignored the time unit "ns":
np.add(arr, arr, dtype="m8[ns]")
np.maximum.reduce(arr, dtype="m8[ns]")

# The following previously did use "ns" (as opposed to `arr.dtype`)
np.add(3, 5, dtype="m8[ns]")  # Now return generic time units
np.maximum(arr, arr, dtype="m8[ns]")  # Now returns "s" (from `arr`)

对于像 `np.sum` 这样在内部使用这些函数的函数也适用。此更改对于实现 NumPy 内部的一致处理是必需的。

如果遇到这些问题,在大多数情况下,请例如传递 `dtype=np.timedelta64`,这清楚地表示了一个没有定义单位或字节序的通用 `timedelta64`。如果您需要精确指定输出 dtype,可以通过转换输入或使用 `out=` 提供输出数组来完成。

NumPy 将来可能会允许在此处提供精确的输出 `dtype`,届时将发出 `FutureWarning`。

(gh-18718)

ufunc `signature=...` 和 `dtype=...` 的泛化和类型转换#

由于 1.21 中由于类型提升的变化,`np.ufunc(1.0, 1.0, signature=...)` 或 `np.ufunc(1.0, 1.0, dtype=...)` 的行为可能与 1.20 不同。以前使用 `signature` 时,对输入的类型转换检查会放宽,这可能导致不安全地向下转换输入,特别是与 `casting="unsafe"` 结合使用时。

类型转换现在保证是安全的。如果 `signature` 只提供了部分信息,例如使用 `signature=("float64", None, None)`,这可能导致找不到循环(出错)。在这种情况下,必须提供完整的 `signature` 来强制转换输入。如果使用 `dtype="float64"` 或仅设置输出(例如 `signature=(None, None, "float64")`),则不会发生变化。我们预计只有很少的用户会受到此更改的影响。

此外,`dtype="float64"` 的含义略有修改,现在仅严格强制正确的输出(而非输入) DType。这意味着它现在始终等同于

signature=(None, None, "float64")

(如果 ufunc 有两个输入和一个输出)。由于这可能导致在某些情况下找不到循环,NumPy 通常还会搜索循环

signature=("float64", "float64", "float64")

如果第一次搜索失败。将来,此行为可能会根据需要进行自定义,以实现更复杂 ufuncs 的预期结果。(对于某些通用函数,例如 `np.ldexp`,输入可以具有不同的 DTypes。)

(gh-18880)

Distutils 对 clang 强制执行严格浮点模型#

使用 clang 编译时,NumPy distutils 现在将始终添加 `-ffp-exception-behavior=strict` 编译器标志。Clang 默认使用非严格版本,这允许编译器生成不正确设置浮点警告/错误的代码。

(gh-19049)

C API 更改#

使用 `ufunc->type_resolver` 和“类型元组”#

NumPy 现在在调用类型解析函数之前会规范化“类型元组”参数。请注意,使用此类型解析器是遗留行为,NumPy 在可能的情况下不会这样做。强烈不建议调用 `ufunc->type_resolver` 或 `PyUFunc_DefaultTypeResolver`,现在如果这样做,将强制执行规范化的类型元组。请注意,这不会影响提供类型解析器,在大多数情况下,类型解析器应该仍然有效。如果您有意外的调用类型解析器的用例,请告知 NumPy 开发人员,以便找到解决方案。

(gh-18718)

新功能#

为处理平台特定的 `numpy.number` 精度添加了 mypy 插件#

现在提供了一个 mypy 插件,用于自动分配某些 `numpy.number` 子类的(平台相关的)精度,包括 `int_`、`intp` 和 `longlong` 等。有关受影响类的全面概述,请参阅关于 标量类型 的文档。

请注意,虽然使用该插件是完全可选的,但如果没有它,上述类的精度将推断为 Any

要启用该插件,必须将其添加到 mypy 的 配置文件中。

[mypy]
plugins = numpy.typing.mypy_plugin

(gh-17843)

让 mypy 插件管理扩展精度 `numpy.number` 子类#

numpy/numpy#17843 中引入的 mypy 插件已得到扩展:该插件现在会移除平台上不可用的平台特定扩展精度类型的注解。例如,当 `float128` 不可用时,它会移除 `float128` 的注解。

在没有插件的情况下,就 mypy 而言,所有扩展精度类型都将在所有平台上可用。

要启用该插件,必须将其添加到 mypy 的 配置文件中。

[mypy]
plugins = numpy.typing.mypy_plugin

(gh-18322)

用于打印浮点值的新 `min_digits` 参数#

在 dragon4 浮点打印函数 `format_float_positional` 和 `format_float_scientific` 中添加了一个新的 `min_digits` 参数。当在 `unique=True` 模式下打印时,此关键字参数保证至少会打印给定的位数,即使额外的位数不是唯一指定值所必需的。它是 `precision` 参数的对应项,`precision` 参数设置要打印的最大位数。当 `unique=False` 且处于固定精度模式时,它没有影响,`precision` 参数固定了打印的位数。

(gh-18629)

f2py 现在可以识别 Fortran 抽象接口块#

f2py 现在可以解析抽象接口块。

(gh-18695)

通过环境变量配置 BLAS 和 LAPACK#

可以通过使用 `NPY_BLAS_LIBS` 和 `NPY_LAPACK_LIBS` 环境变量来绕过已安装 BLAS 和 LAPACK 库的自动检测。相反,将直接使用这些环境变量中的链接标志,并且假定语言为 F77。这对于自动化构建尤其有用,因为已安装的 BLAS 和 LAPACK 是精确已知的。一个用例是通过存根库链接在运行时替换实际实现。

如果设置了 `NPY_CBLAS_LIBS`(可选,除了 `NPY_BLAS_LIBS`),它也将被使用,通过定义 `HAVE_CBLAS` 并将环境变量内容附加到链接标志。

(gh-18737)

为 `ndarray` 添加了一个运行时可下标的别名#

`numpy.typing.NDArray` 已被添加,它是 `np.ndarray[Any, np.dtype[~Scalar]]` 的运行时可下标别名。新的类型别名可用于注释具有给定 dtype 和未指定形状的数组。1

1 NumPy 在 1.21 版本中不支持数组形状的注解,未来预计会发生变化(参见 PEP 646)。

示例#

>>> import numpy as np
>>> import numpy.typing as npt

>>> print(npt.NDArray)
numpy.ndarray[typing.Any, numpy.dtype[~ScalarType]]

>>> print(npt.NDArray[np.float64])
numpy.ndarray[typing.Any, numpy.dtype[numpy.float64]]

>>> NDArrayInt = npt.NDArray[np.int_]
>>> a: NDArrayInt = np.arange(10)

>>> def func(a: npt.ArrayLike) -> npt.NDArray[Any]:
...     return np.array(a)

(gh-18935)

改进#

`numpy.unwrap` 的任意 `period` 选项#

解相位间隔的大小不再限于 `2 * pi`。这对于解相位(例如角度)尤其有用,但也可用于其他区间。

>>> phase_deg = np.mod(np.linspace(0,720,19), 360) - 180
>>> phase_deg
array([-180., -140., -100.,  -60.,  -20.,   20.,   60.,  100.,  140.,
       -180., -140., -100.,  -60.,  -20.,   20.,   60.,  100.,  140.,
       -180.])

>>> unwrap(phase_deg, period=360)
array([-180., -140., -100.,  -60.,  -20.,   20.,   60.,  100.,  140.,
        180.,  220.,  260.,  300.,  340.,  380.,  420.,  460.,  500.,
        540.])

(gh-16987)

`np.unique` 现在返回单个 `NaN`#

当 `np.unique` 操作包含多个 `NaN` 条目的数组时,其返回值会包含每个对应于原始数组中 `NaN` 的条目。现在已改进此行为,返回的数组只包含一个 `NaN` 作为最后一个元素。

对于复数数组,所有 `NaN` 值都被视为等效(无论 `NaN` 是在实部还是虚部)。作为返回数组的代表,选择词典顺序中最小的那个 - 请参阅 `np.sort` 以了解复数数组的词典顺序定义。

(gh-18070)

`Generator.rayleigh` 和 `Generator.geometric` 性能提升#

Rayleigh 和 geometric 随机变数生成在 `Generator` 中的性能有所提高。这些都是指数随机变量的变换,基于 log 的慢速逆 cdf 变换已被替换为基于 Ziggurat 的指数变数生成器。

此更改会破坏从这些分布中生成变数时的变数流。

(gh-18666)

占位符注解已得到改进#

所有先前被注解为 `typing.Any` 的占位符注解都已得到改进。在适当的情况下,它们已被替换为显式的函数定义、类或其他杂项对象。

(gh-18934)

性能改进#

NumPy 数组整数除法的性能提升#

当除数是常量时,NumPy 数组的整数除法现在使用 libdivide。通过使用 libdivide 和其他小优化,速度有了很大提升。`//` 运算符和 `np.floor_divide` 利用了这些新变化。

(gh-17727)

针对小数组的 `np.save` 和 `np.load` 性能提升#

对于小数组,`np.save` 现在速度快了很多。

np.load 在序列化版本 >= 3.0 时,对小型数组也更快。

这两种方法都是通过移除仅与 Python 2 相关的检查来实现的,同时仍能与可能由 Python 2 创建的数组保持兼容。

(gh-18657)

更改#

numpy.piecewise 的输出类现在与输入类匹配#

ndarray 子类用作 piecewise 的输入时,它们会被传递给函数。现在输出也将是相同的子类。

(gh-18110)

启用 Accelerate Framework#

随着 macOS 11.3 的发布,numpy 在使用 Accelerate Framework 的 BLAS 和 LAPACK 实现时遇到的一些问题应该已经得到解决。此更改将 Accelerate Framework 作为一个选项在 macOS 上启用。如果发现其他问题,请使用开发者反馈助手工具 (https://developer.apple.com/bug-reporting/) 针对 Accelerate 提交 bug 报告。我们打算及时解决问题,并计划继续支持和更新我们的 BLAS 和 LAPACK 库。

(gh-18874)