NumPy 1.25.0 发行说明#

NumPy 1.25.0 版本继续致力于改进 dtype 的处理和提升、提高执行速度以及澄清文档。此外,还为未来的 NumPy 2.0.0 版本做了准备工作,导致大量新的和已过期的弃用。主要亮点包括:

  • 支持 MUSL,现在有 MUSL wheel。

  • 支持富士通 C/C++ 编译器。

  • einsum 现在支持对象数组

  • 支持原地矩阵乘法 (@=)。

Python 3.12 发布时,我们将发布 NumPy 1.26。这是必要的,因为 Python 3.12 已放弃 distutils,我们将切换到使用 meson 进行未来的构建。下一个主线版本将是 NumPy 2.0.0。我们计划 2.0 系列仍将支持针对早期 NumPy 版本构建的下游项目。

此版本支持的 Python 版本是 3.9-3.11。

弃用#

  • np.core.MachAr 已弃用。它是私有 API。在 np.core 中定义的名称通常应视为私有。

    (gh-22638)

  • np.finfo(None) 已弃用。

    (gh-23011)

  • np.round_ 已弃用。请改用 np.round

    (gh-23302)

  • np.product 已弃用。请改用 np.prod

    (gh-23314)

  • np.cumproduct 已弃用。请改用 np.cumprod

    (gh-23314)

  • np.sometrue 已弃用。请改用 np.any

    (gh-23314)

  • np.alltrue 已弃用。请改用 np.all

    (gh-23314)

  • 只有 ndim-0 数组被视为标量。NumPy 过去将所有大小为 1 的数组(例如,np.array([3.14]))视为标量。将来,这将仅限于 ndim 为 0 的数组(例如,np.array(3.14))。以下表达式将报告弃用警告:

    a = np.array([3.14])
    float(a)  # better: a[0] to get the numpy.float or a.item()
    
    b = np.array([[3.14]])
    c = numpy.random.rand(10)
    c[0] = b  # better: c[0] = b[0, 0]
    

    (gh-10615)

  • np.find_common_type 已弃用。numpy.find_common_type 现已弃用,应替换为 numpy.result_typenumpy.promote_types。大多数用户会将 find_common_type 的第二个 scalar_types 参数留空为 [],在这种情况下,np.result_typenp.promote_types 都更快且更健壮。当不使用 scalar_types 时,主要区别在于,替换函数有意将非本机字节序转换为本机字节序。此外,find_common_type 返回 object dtype 而不是提升失败。这导致当输入不全是数字时出现差异。重要的是,对于 timedelta/datetime 等情况,NumPy 的提升规则目前有时令人惊讶,也会发生这种情况。

    scalar_types 参数不为 [] 时,情况会更复杂。在大多数情况下,使用 np.result_type 并传递 Python 值 00.00j 的结果与在 scalar_types 中使用 intfloatcomplex 相同。

    当构造 scalar_types 时,np.result_type 是正确的替代方案,并且可以传递 np.float32(0.0) 这样的标量值。传递非 0 值可能会导致值检查行为(np.find_common_type 从未使用过,且 NEP 50 在未来可能会改变)。在这种情况下,行为的主要可能变化是当数组类型为有符号整数而标量类型为无符号整数时。

    如果您不确定如何替换 scalar_types 的用法或何时可能出现非数字 dtype,请随时提交 NumPy issue 以寻求帮助。

    (gh-22539)

已过期的弃用#

  • np.core.macharnp.finfo.machar 已被移除。

    (gh-22638)

  • 当 dtype 不是数字类型(且正数未定义)时,+arr 现在将引发错误。

    (gh-22998)

  • 现在必须将序列传递给堆叠函数族(stackvstackhstackdstackcolumn_stack)。

    (gh-23019)

  • np.clip 现在默认进行同类型转换。回退到不安全转换在 NumPy 1.17 中已被弃用。

    (gh-23403)

  • np.clip 现在将传播作为 minmax 传递的 np.nan 值。以前,标量 NaN 通常会被忽略。这在 NumPy 1.17 中已被弃用。

    (gh-23403)

  • np.dual 子模块已被移除。

    (gh-23480)

  • NumPy 现在总是忽略类数组(定义了其中一个数组协议)的序列行为。(弃用始于 NumPy 1.20)

    (gh-23660)

  • astypeasarray 等数组创建函数中,当转换为子数组 dtype 时出现的特殊 FutureWarning 现已确定。现在的行为始终与子数组 dtype 被封装到单个字段中(这曾是之前的解决方法)时的行为相同。(自 NumPy 1.20 起的 FutureWarning)

    (gh-23666)

  • ==!= 警告已最终确定。数组上的 ==!= 运算符现在总是:

    • 在比较过程中发生错误时引发异常,例如数组形状不兼容时(np.array([1, 2]) == np.array([1, 2, 3]))。

    • 当值本质上不可比较时(例如具有不同的 dtype),返回一个全为 True 或全为 False 的数组。例如 np.array(["a"]) == np.array([1])

      这模仿了 Python 在比较不兼容类型(如 "a" == 1"a" != 1)时返回 FalseTrue 的行为。长期以来,这些操作会引发 DeprecationWarningFutureWarning

    (gh-22707)

  • Nose 支持已被移除。NumPy 在 2018 年切换到使用 pytest,而 nose 多年来一直未维护。我们一直保留 NumPy 对 nose 的支持,以避免破坏可能正在使用它但尚未切换到 pytest 或其他测试框架的下游项目。随着 Python 3.12 的到来,未经修补的 nose 将引发错误。现在是时候向前看了。

    移除的装饰器:

    • raises

    • slow

    • setastest

    • skipif

    • knownfailif

    • deprecated

    • parametrize

    • _needs_refcount

    这些不应与 pytest 版本中名称相似的装饰器混淆,例如 pytest.mark.slow、pytest.mark.skipif、pytest.mark.parametrize。

    移除的函数:

    • Tester

    • import_nose

    • run_module_suite

    (gh-23041)

  • numpy.testing.utils 垫片已被移除。自 2019 年以来,从 numpy.testing.utils 垫片导入已被弃用,现在该垫片已移除。所有导入都应直接从 numpy.testing 进行。

    (gh-23060)

  • 禁用调度的环境变量已被移除。NUMPY_EXPERIMENTAL_ARRAY_FUNCTION 环境变量的支持已被移除。此变量禁用了通过 __array_function__ 进行的调度。

    (gh-23376)

  • 对将 y= 作为 out= 别名的支持已被移除。fixisposinfisneginf 函数曾允许使用 y= 作为 out= 的(已弃用)别名。现在不再支持此功能。

    (gh-23376)

兼容性说明#

  • busday_count 方法现在能正确处理 begindates 晚于 enddates 的情况。以前,enddates 会被包含在内,尽管文档声明它总是被排除在外。

    (gh-23229)

  • 以前,当使用 np.equalnp.not_equal 比较 datetimes 和 timedelta 时,NumPy 允许使用 casting="unsafe" 进行比较。现在此操作将失败。使用 dtype 关键字参数强制输出 dtype 可以使操作成功,但我们不推荐这样做。

    (gh-22707)

  • 当使用 np.load 从文件句柄加载数据时,如果句柄位于文件末尾(这在重复调用 np.load 读取多个数组时可能发生),以前在 allow_pickle=False 时会引发 ValueError,在 allow_pickle=True 时会引发 OSError。现在,两种情况下都将引发 EOFError

    (gh-23105)

np.pad 使用 mode=wrap 时,填充严格为原始数据的倍数#

基于早期版本 pad 且使用 mode="wrap" 的代码,当填充大小大于初始数组时将返回不同的结果。

现在,即使填充大小大于初始数组,使用 mode=wrapnp.pad 也会始终使用原始数据的严格倍数填充空间。

(gh-22575)

Cython long_tulong_t 已移除#

long_tulong_t 曾是 longlong_tulonglong_t 的别名,并且容易混淆(Python 2 的遗留问题)。此更改可能导致错误:

'long_t' is not a type identifier
'ulong_t' is not a type identifier

我们建议使用位大小的类型,例如 cnp.int64_t,或使用 cnp.intp_t(在 32 位系统上为 32 位,在 64 位系统上为 64 位,这与索引最兼容)。如果需要 C 的 long,请使用普通的 longnpy_longcnp.int_t 也是 long(NumPy 的默认整数)。然而,在 64 位 Windows 上,long 是 32 位,我们甚至可能希望在 NumPy 中调整这一点。(如果您对此感到好奇,请随时联系 NumPy 开发人员。)

(gh-22637)

修改了 ufuncaxes 参数不正确时的错误消息和类型#

当向 ufunc(..., axes=[...])` 传递错误的 axes 值时,错误消息和类型已更改。现在的消息更能说明问题,如果值不匹配,将引发 AxisError。对于无效的输入类型,仍将引发 TypeError

(gh-22675)

定义了 __array_ufunc__ 的类数组现在可以在用作 where 时覆盖 ufunc#

如果 numpy.ufuncwhere 关键字参数是 numpy.ndarray 的子类,或者是定义了 numpy.class.__array_ufunc__ 的鸭子类型,它就可以使用与输入和输出参数相同的机制来覆盖 ufunc 的行为。请注意,为了使其正常工作,where.__array_ufunc__ 的实现必须解包 where 参数,将其传递给 ufunc 的默认实现,或者对于 numpy.ndarray 子类,在使用 super().__array_ufunc__ 之前。

(gh-23240)

默认情况下,针对 NumPy C API 编译现在向后兼容#

NumPy 现在默认公开 C-API 的向后兼容子集。这使得 oldest-supported-numpy 的使用变得不必要。库可以通过使用以下方式覆盖默认的最小版本以实现兼容性:

#define NPY_TARGET_VERSION NPY_1_22_API_VERSION

在包含 NumPy 之前,或通过向编译器传递等效的 -D 选项。NumPy 1.25 的默认值为 NPY_1_19_API_VERSION。由于 NumPy 1.19 C API 与 NumPy 1.16 的 C API 相同,因此生成程序将与 NumPy 1.16 兼容(从 C-API 的角度来看)。此默认值将在未来的非错误修复版本中增加。您仍然可以针对旧的 NumPy 版本进行编译,并在新的版本上运行。

欲了解更多详情,请参阅面向下游包作者

(gh-23528)

新特性#

np.einsum 现在接受 object dtype 的数组#

该代码路径将对对象 dtype 数组调用 Python 运算符,与 np.dotnp.matmul 类似。

(gh-18053)

添加对原地矩阵乘法的支持#

现在可以通过 @= 运算符执行原地矩阵乘法。

>>> import numpy as np

>>> a = np.arange(6).reshape(3, 2)
>>> print(a)
[[0 1]
 [2 3]
 [4 5]]

>>> b = np.ones((2, 2), dtype=int)
>>> a @= b
>>> print(a)
[[1 1]
 [5 5]
 [9 9]]

(gh-21120)

添加了 NPY_ENABLE_CPU_FEATURES 环境变量#

用户现在可以通过指定 NPY_ENABLE_CPU_FEATURES 环境变量,在运行时选择仅启用部分内置 CPU 特性。请注意,这些指定的特性必须在基线之外,因为基线特性总是被假定启用。如果尝试启用您的 CPU 不支持或 NumPy 未内置的特性,将引发错误。

(gh-22137)

NumPy 现在拥有一个 np.exceptions 命名空间#

NumPy 现在拥有一个专用的命名空间,其中包含了大多数异常和警告。所有这些在主命名空间中仍然可用,尽管有些将来可能会缓慢移动。主要原因是增加可发现性并添加未来的异常。

(gh-22644)

np.linalg 函数现在返回命名元组(NamedTuples)#

返回元组的 np.linalg 函数现在返回命名元组。这些函数是 eig()eigh()qr()slogdet()svd()。在这些函数通过特定关键字参数(如 svd(compute_uv=False))返回非元组的情况下,返回类型保持不变。

(gh-22786)

np.char 中的字符串函数兼容 NEP 42 自定义 dtypes#

表示 Unicode 字符串或字节字符串的自定义 dtype 现在可以传递给 np.char 中的字符串函数。

(gh-22863)

现在可以从字符串抽象 dtype 类创建字符串 dtype 实例#

现在可以创建一个带大小的字符串 dtype 实例,而无需使用 dtype 的字符串名称。例如,type(np.dtype('U'))(8) 将创建一个等效于 np.dtype('U8') 的 dtype。此功能在编写处理字符串 dtype 类的通用代码时最有用。

(gh-22963)

富士通 C/C++ 编译器现已支持#

已添加对富士通编译器的支持。要使用富士通编译器进行构建,请运行:

python setup.py build -c fujitsu

SSL2 现已支持#

已添加对 SSL2 的支持。SSL2 是一个提供 OpenBLAS 兼容 GEMM 函数的库。要启用 SSL2,需要编辑 site.cfg 并使用富士通编译器进行构建。请参阅 site.cfg.example。

(gh-22982)

改进#

NDArrayOperatorsMixin 指定它没有 __slots__#

NDArrayOperatorsMixin 类现在指定它不包含 __slots__,确保子类现在可以在 Python 中使用此特性。

(gh-23113)

修复复数零的幂运算#

对于复数,np.power 现在对 0^{non-zero} 返回不同的结果。请注意,只有当指数的实部大于零时,该值才被定义。以前,除非虚部严格为零,否则会返回 NaN。返回值现在是 0+0j0-0j

(gh-18535)

新的 DTypePromotionError#

NumPy 现在有一个新的 DTypePromotionError,当两个 dtype 无法提升为共同的 dtype 时使用,例如

np.result_type("M8[s]", np.complex128)

会引发此新异常。

(gh-22707)

np.show_config 使用 Meson 中的信息#

构建和系统信息现在包含来自 Meson 的信息。np.show_config 现在有一个新的可选参数 mode,用于帮助自定义输出。

(gh-22769)

修复 np.ma.diff 在使用 prepend/append 参数调用时未保留掩码的问题。#

现在,使用 prepend 和/或 append 参数调用 np.ma.diff 将返回一个保留输入掩码的 MaskedArray

以前,会返回一个不带掩码的 MaskedArray

(gh-22776)

更正了 Cython 中 NumPy C-API 的错误处理#

许多在 Cython 中使用的 NumPy C 函数缺少正确的错误指示符,例如 except -1except *。现在已添加这些指示符。

(gh-22997)

能够直接派生随机数生成器#

numpy.random.Generator.spawn 现在允许通过 numpy.random.SeedSequence.spawn 机制直接派生新的独立子生成器。numpy.random.BitGenerator.spawn 对底层比特生成器也做同样的事情。

此外,numpy.random.BitGenerator.seed_seq 现在可以直接访问用于初始化比特生成器的种子序列。例如,这使得:

seed = 0x2e09b90939db40c400f8f22dae617151
rng = np.random.default_rng(seed)
child_rng1, child_rng2 = rng.spawn(2)

# safely use rng, child_rng1, and child_rng2

以前,如果不显式传递 SeedSequence,这很难做到。更多信息请参阅 numpy.random.SeedSequence

(gh-23195)

numpy.logspace 现在支持非标量 base 参数#

numpy.logspacebase 参数现在可以是类数组(array-like),只要它能与 startstop 参数进行广播。

(gh-23275)

np.ma.dot() 现在支持非二维数组#

以前,np.ma.dot() 仅在 ab 均为二维数组时才起作用。现在,它也支持非二维数组,就像 np.dot() 一样。

(gh-23322)

在 repr 中显式显示 .npz 文件的键#

打印 NpzFile 时会显示已加载的 .npz 文件的键。

>>> npzfile = np.load('arr.npz')
>>> npzfile
NpzFile 'arr.npz' with keys arr_0, arr_1, arr_2, arr_3, arr_4...

(gh-23357)

NumPy 现在在 np.dtypes 中公开 DType 类#

新的 numpy.dtypes 模块现在公开了 DType 类,并将包含未来与 dtype 相关的功能。大多数用户应该没有直接使用这些类的需求。

(gh-23358)

在 .npy 或 .npz 文件中保存之前丢弃 dtype 元数据#

目前,包含带有元数据的 dtype 表的 *.npy 文件无法读回。现在,np.savenp.savez 在保存前会丢弃元数据。

(gh-23371)

numpy.lib.recfunctions.structured_to_unstructured 在更多情况下返回视图#

如果字段之间的步幅是常量,structured_to_unstructured 现在会返回一个视图。以前,字段之间的填充或反转的字段会导致复制。此更改仅适用于 ndarraymemmaprecarray。对于所有其他数组子类,行为保持不变。

(gh-23652)

有符号和无符号整数始终正确比较#

uint64int64 在 NumPy 中混合使用时,NumPy 通常会将两者都提升为 float64。这种行为可能存在争议,但对于 ==<= 等比较而言会造成混淆,因为返回的结果可能不正确,但由于结果是布尔值,所以转换被隐藏了。NumPy 现在将通过避免转换为浮点数来返回这些情况下的正确结果。

(gh-23713)

性能改进和更改#

在启用 AVX-512 的处理器上更快地执行 np.argsort#

np.argsort 的 32 位和 64 位快速排序算法在支持 AVX-512 指令集的处理器上获得高达 6 倍的速度提升。

感谢 英特尔公司赞助这项工作。

(gh-23707)

在启用 AVX-512 的处理器上更快地执行 np.sort#

对于 16 位和 64 位 dtypes 的快速排序算法,在支持 AVX-512 指令集的处理器上,速度分别提高了高达 15 倍和 9 倍。

感谢 英特尔公司赞助这项工作。

(gh-22315)

__array_function__ 机制现在快得多#

NumPy 中大多数函数的开销现在更小,尤其是在使用关键字参数时。这一改变显著加快了许多简单函数调用的速度。

(gh-23020)

ufunc.at 可以快得多#

通用 ufunc.at 可以快达 9 倍。实现此加速的条件是:

  • 操作数对齐

  • 无类型转换

如果 ufunc 在一维参数上具有满足上述条件的适当索引循环,ufunc.at 可以快达 60 倍(额外加速 7 倍)。适当的索引循环已添加到 addsubtractmultiplyfloor_dividemaximumminimumfmaxfmin 中。

内部逻辑类似于常规 ufunc 所使用的逻辑,后者也具有快速路径。

感谢 D. E. Shaw 集团赞助这项工作。

(gh-23136)

NpzFile 进行成员测试更快#

如果成员测试成功,对 NpzFile 的成员测试将不再解压缩档案。

(gh-23661)

更改#

np.r_[]np.c_[] 与某些标量值#

在极少数情况下,主要使用带标量的 np.r_ 可能会导致不同的结果。以下突出显示了主要潜在变化:

>>> np.r_[np.arange(5, dtype=np.uint8), -1].dtype
int16  # rather than the default integer (int64 or int32)
>>> np.r_[np.arange(5, dtype=np.int8), 255]
array([  0,   1,   2,   3,   4, 255], dtype=int16)

其中第二个示例返回:

array([ 0,  1,  2,  3,  4, -1], dtype=int8)

第一个是由于有符号整数标量与无符号整数数组混合,而第二个是由于 255 不适合 int8,并且 NumPy 目前正在检查值以使其正常工作。(请注意,由于 NEP 50,第二个示例预计将来会改变;届时它将引发错误。)

(gh-22539)

大多数 NumPy 函数被封装为 C 可调用对象#

为了加快 __array_function__ 调度,大多数 NumPy 函数现在被封装为 C 可调用对象,而不是真正的 Python 函数或 C 方法。它们看起来和感觉仍然与以前相同(就像一个 Python 函数),这应该只会提高性能和用户体验(更清晰的回溯)。但是,如果此更改由于某种原因使您的程序混淆,请告知 NumPy 开发人员。

(gh-23020)

C++ 标准库使用#

NumPy 构建现在依赖于 C++ 标准库,因为 numpy.core._multiarray_umath 扩展库是使用 C++ 链接器链接的。

(gh-23601)