NumPy 1.17.0 版本说明#

此 NumPy 版本包含许多新功能,这些功能应大幅提高其性能和实用性,请参阅下面的“亮点”以了解摘要。支持的 Python 版本为 3.5-3.7,请注意已放弃 Python 2.7。Python 3.8b2 应该可以与发布的源代码包一起使用,但没有未来的保证。

下游开发人员应使用 Cython >= 0.29.11 以获得 Python 3.8 支持,并使用 OpenBLAS >= 3.7(目前尚未发布)以避免在 Skylake 架构上出现问题。PyPI 上的 NumPy 轮子是从 OpenBLAS 开发分支构建的,以避免这些问题。

亮点#

  • 添加了一个新的可扩展的 random 模块,以及四个可选的随机数生成器和改进的种子设计,用于并行进程。当前可用的位生成器是MT19937PCG64PhiloxSFC64。请参阅下面“新功能”部分。

  • NumPy 的 FFT 实现已从 fftpack 更改为 pocketfft,从而实现了更快、更准确的转换以及对素数长度数据集的更好处理。请参阅下面“改进”部分。

  • 新的基数排序和 timsort 排序方法。目前无法选择使用哪一种。它们与数据类型紧密关联,并且在将 stablemergesort 作为方法传递时使用。请参阅下面“改进”部分。

  • 现在默认情况下可以覆盖 numpy 函数,请参阅下面的 __array_function__

新函数#

弃用功能#

numpy.polynomial 函数在传递 float 代替 int 时会发出警告#

以前,此模块中的函数如果提供的是整数型浮点数(1.02.0 等),则会接受 float 值。为了与 NumPy 的其余部分保持一致,现在已弃用此做法,将来会引发 TypeError

同样,传递类似 0.5 的浮点数来代替整数现在会引发 TypeError,而不是之前的 ValueError

弃用 numpy.distutils.exec_commandtemp_file_name#

这些函数的内部使用已重构,并且有更好的替代方案。将 exec_command 替换为 subprocess.Popen,并将 temp_file_name 替换为 tempfile.mkstemp

C-API 封装数组的可写标志#

当从 C-API 创建数组以包装指向数据的指针时,我们对数据读写性质的唯一指示是在创建期间设置的 writeable 标志。强制将标志设置为可写是危险的。将来将无法从 python 将可写标志切换为 True。此弃用不应影响许多用户,因为实际上以这种方式创建的数组非常少见,并且只能通过 NumPy C-API 使用。

numpy.nonzero 不应再用于 0d 数组#

numpy.nonzero 在 0d 数组上的行为令人惊讶,使其几乎总是使用不正确。如果预期的旧行为,则可以使用 nonzero(atleast_1d(arr)) 代替 nonzero(arr) 来保留它而不发出警告。在未来的版本中,这很可能会引发 ValueError

写入 numpy.broadcast_arrays 的结果将发出警告#

通常,numpy.broadcast_arrays 返回具有内部重叠的可写数组,这使得写入不安全。未来的版本将 writeable 标志设置为 False,并要求用户手动将其设置为 True,如果他们确定这就是他们想要做的。现在写入它将发出弃用警告,其中包含设置 writeable 标志为 True 的说明。请注意,如果在设置之前检查标志,会发现它已经为 True。但是,显式设置它(正如在将来的版本中需要做的那样)会清除用于产生弃用警告的内部标志。为了减轻混淆,在访问 writeable 标志状态时,将发出额外的FutureWarning 以阐明这种矛盾。

请注意,对于 C 端缓冲区协议,这样的数组将立即返回只读缓冲区,除非请求可写缓冲区。如果请求可写缓冲区,则会发出警告。使用 cython 时,应将 const 限定符与这些数组一起使用以避免警告(例如 cdef const double[::1] view)。

未来的更改#

在未来的版本中,dtype 中的 shape-1 字段不会折叠为标量#

当前,指定为 [(name, dtype, 1)]"1type" 的字段被解释为标量字段(即与 [(name, dtype)][(name, dtype, ())] 相同)。这现在会引发 FutureWarning;在未来的版本中,它将被解释为 shape-(1,) 字段,即与 [(name, dtype, (1,))]"(1,)type" 相同(与 [(name, dtype, n)] / "ntype"n>1 相同,这已经等同于 [(name, dtype, (n,)] / "(n,)type")。

兼容性说明#

float16 次正规舍入#

从不同的浮点精度转换为 float16 在某些极端情况下使用了不正确的舍入。这意味着在极少数情况下,次正规结果现在将向上舍入而不是向下舍入,从而更改结果的最后一位 (ULP)。

使用 divmod 时的带符号零#

1.12.0 版本开始,当使用 divmodfloor_divide 函数且结果为零时,NumPy 错误地返回了一个负号零。例如:

>>> np.zeros(10)//1
array([-0., -0., -0., -0., -0., -0., -0., -0., -0., -0.])

在此版本中,结果已正确返回为正号零。

>>> np.zeros(10)//1
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])

MaskedArray.mask 现在返回掩码的视图,而不是掩码本身#

返回掩码本身是不安全的,因为它可以在原地重新整形,这会违反掩码数组代码的预期。mask 的行为现在与 data 一致,后者也返回一个视图。

如果需要,仍然可以使用 ._mask 访问底层掩码。包含 assert x.mask is not y.mask 或类似内容的测试需要更新。

不要在 numpy.frombuffer 中查找 __buffer__ 属性#

numpy.frombuffer 中查找 __buffer__ 属性未在文档中说明且无效。此代码已被删除。如果需要,请改用 frombuffer(memoryview(obj), ...)

takechooseput 中,out 缓冲区用于处理内存重叠#

如果提供了这些函数的 out 参数并且它与其他参数存在内存重叠,则现在对其进行缓冲以避免依赖于顺序的行为。

加载时的解串需要显式选择加入#

loadlib.format.read_array 函数接受一个 allow_pickle 关键字参数,现在默认为 False,以响应 CVE-2019-6446

旧随机模块中随机流的潜在更改#

由于将 log 应用于随机浮点数的错误,当从 betabinomiallaplacelogisticlogseriesmultinomial 采样时,如果底层 MT19937 随机流中生成了 0,则流可能会发生变化。发生这种情况的概率为 \(10^{53}\) 分之一,因此对于任何给定的种子,流发生变化的概率极小。如果在底层生成器中遇到 0,则现在会丢弃产生的错误值(numpy.infnumpy.nan)。

i0 现在始终返回与输入形状相同的输出#

以前,输出会被压缩,例如,只有一个元素的输入将返回一个数组标量,形状为 (10, 1) 的输入将产生不能与输入广播的结果。

请注意,我们通常建议使用 SciPy 实现而不是 NumPy 实现:它是一个用 C 编写的正确的 ufunc,速度快了一个数量级以上。

can_cast 不再假设所有不安全转换都是允许的#

以前,对于 casting='unsafe'can_cast 几乎对所有输入都返回 True,即使在无法进行转换的情况下,例如从结构化 dtype 转换为常规 dtype。这个问题已得到修复,使其与使用例如 .astype 方法的实际转换更加一致。

ndarray.flags.writeable 可以更频繁地切换为 true#

在极少数情况下,虽然基数组是可写的,但无法将数组从不可写切换为可写。如果中间 ndarray.base 对象是可写的,则可能会发生这种情况。以前,只有最深层的基对象被考虑用于此决策。但是,在极少数情况下,此对象没有必要的信息。在这种情况下,永远不允许切换为可写。这个问题现在已得到修复。

C API 更改#

维度或步长输入参数现在通过 npy_intp const* 传递#

以前,这些函数参数被声明为更严格的 npy_intp*,这阻止了调用者传递常量数据。此更改向后兼容,但现在允许如下代码:

npy_intp const fixed_dims[] = {1, 2, 3};
// no longer complains that the const-qualifier is discarded
npy_intp size = PyArray_MultiplyList(fixed_dims, 3);

新功能#

具有可选随机数生成器的新的可扩展 numpy.random 模块#

添加了一个新的可扩展 numpy.random 模块,以及四个可选的随机数生成器和改进的种子设计,用于并行进程。当前可用的 位生成器MT19937PCG64PhiloxSFC64PCG64 是新的默认值,而 MT19937 保留用于向后兼容性。请注意,旧的随机模块保持不变,现在已冻结,您的当前结果不会改变。更多信息可在 API 更改说明顶级视图 文档中找到。

libFLAME#

支持使用 libFLAME 线性代数包作为 LAPACK 实现来构建 NumPy,有关详细信息,请参见 libFLAME

用户定义的 BLAS 检测顺序#

现在,distutils 使用一个环境变量(逗号分隔,不区分大小写)来确定 BLAS 库的检测顺序。默认情况下,NPY_BLAS_ORDER=mkl,blis,openblas,atlas,accelerate,blas。但是,要强制使用 OpenBLAS,只需执行以下操作:

NPY_BLAS_ORDER=openblas python setup.py build

这将强制使用 OpenBLAS。对于那些安装了 MKL 但希望尝试不同实现的用户来说,这可能很有帮助。

用户自定义 LAPACK 检测顺序#

numpy.distutils 现在使用一个环境变量(逗号分隔,不区分大小写)来确定 LAPACK 库的检测顺序。默认情况下,NPY_LAPACK_ORDER=mkl,openblas,flame,atlas,accelerate,lapack。但是,要强制使用 OpenBLAS,只需执行以下操作:

NPY_LAPACK_ORDER=openblas python setup.py build

这将强制使用 OpenBLAS。对于那些安装了 MKL 但希望尝试不同实现的用户来说,这可能很有帮助。

Timsort 和基数排序已取代归并排序用于稳定排序#

基数排序和 Timsort 都已实现,现在已取代归并排序。由于需要保持向后兼容性,排序 kind 选项 "stable""mergesort" 已成为彼此的别名,实际的排序实现取决于数组类型。对于大小为 16 位或更小的整型,使用基数排序;对于其余类型,使用 Timsort。Timsort 在包含已排序或接近已排序数据的数据上的性能有所提高,在随机数据上的性能与归并排序类似,并且需要 \(O(n/2)\) 的工作空间。Timsort 算法的详细信息可在 CPython listsort.txt 中找到。

packbitsunpackbits 接受 order 关键字#

order 关键字默认为 big,并将相应地对 **位** 进行排序。对于 'order=big',3 将变为 [0, 0, 0, 0, 0, 0, 1, 1],而对于 order=little,则为 [1, 1, 0, 0, 0, 0, 0, 0]

unpackbits 现在接受 count 参数#

count 允许预先对将要解压的位数进行子集选择,而不是稍后进行重塑和子集选择,从而使 packbits 操作可逆,并减少解压的浪费。大于可用位数的计数将添加零填充。负计数将从末尾修剪位,而不是从开头计数。None 计数将实现解压所有内容的现有行为。

linalg.svdlinalg.pinv 在 Hermitian 输入上的速度可能更快#

这些函数现在接受 hermitian 参数,与 1.14.0 中添加到 linalg.matrix_rank 的参数匹配。

现在支持两个 timedelta64 操作数的 divmod 操作#

divmod 运算符现在处理两个 timedelta64 操作数,类型签名为 mm->qm

fromfile 现在接受 offset 参数#

此函数现在为二进制文件接受 offset 关键字参数,该参数指定文件当前位置的偏移量(以字节为单位)。默认为 0

pad 新增模式“empty”#

此模式将数组填充到所需形状,但不初始化新条目。

浮点标量实现 as_integer_ratio 以匹配内置浮点数#

这将返回一个 (分子,分母) 对,可用于构造 fractions.Fraction

结构化 dtype 对象可以用多个字段名称进行索引#

arr.dtype[['a', 'b']] 现在返回一个与 arr[['a', 'b']].dtype 等效的 dtype,以与 arr.dtype['a'] == arr['a'].dtype 保持一致。

与用字段列表索引的结构化数组的 dtype 一样,此 dtype 的 itemsize 与原始 dtype 相同,但只保留一部分字段。

这意味着 arr[['a', 'b']]arr.view(arr.dtype[['a', 'b']]) 是等效的。

.npy 文件支持 Unicode 字段名称#

引入了新的 3.0 格式版本,它支持具有非 latin1 字段名称的结构化类型。在需要时会自动使用此版本。

改进#

数组比较断言包括最大差异#

来自数组比较测试(例如 testing.assert_allclose)的错误消息现在除了之前的“不匹配”百分比外,还包括“最大绝对差”和“最大相对差”。此信息使更新绝对和相对误差容限更容易。

用 pocketfft 库替换基于 fftpack 的 fft 模块#

两种实现都具有相同的祖先(Paul N. Swarztrauber 编写的 Fortran77 FFTPACK),但 pocketfft 包含额外的修改,在某些情况下可以提高精度和性能。对于包含大素数因子的 FFT 长度,pocketfft 使用 Bluestein 算法,该算法保持 \(O(N log N)\) 的运行时间复杂度,而不是对于素数长度退化为 \(O(N*N)\)。此外,对于具有接近素数长度的实值 FFT 的精度也得到了提高,并且与复值 FFT 的精度相当。

进一步改进 numpy.ctypeslib 中的 ctypes 支持#

添加了一个新的 numpy.ctypeslib.as_ctypes_type 函数,可用于将 dtype 转换为最佳猜测的 ctypes 类型。由于此新函数,numpy.ctypeslib.as_ctypes 现在支持更广泛的数组类型,包括结构体、布尔值和非原生字节序的整数。

numpy.errstate 现在也是一个函数装饰器#

目前,如果您有一个像这样的函数:

def foo():
    pass

并且您想用 errstate 包装整个函数,则必须将其改写为:

def foo():
    with np.errstate(...):
        pass

但是通过此更改,您可以执行以下操作:

@np.errstate(...)
def foo():
    pass

从而节省了一个缩进级别。

numpy.expnumpy.log 的 float32 实现速度提升#

explog 的 float32 实现现在受益于在运行时检测到的 AVX2/AVX512 指令集。exp 的最大 ulp 误差为 2.52,log 的最大 ulp 误差为 3.83。

提高 numpy.pad 的性能#

通过使用预分配数组填充所需填充形状,而不是使用串联,该函数的性能在大多数情况下得到了提高。

numpy.interp 更稳健地处理无穷大#

在某些情况下,interp 以前会返回 nan,现在它返回适当的无穷大。

fromfiletofilendarray.dump 的 Pathlib 支持#

fromfilendarray.ndarray.tofilendarray.dump 现在支持 pathlib.Path 类型的 file/fid 参数。

针对 bool 和 int 类型的专用 isnanisinfisfinite ufunc#

布尔型和整型无法存储 naninf 值,这使我们能够提供比以前的方法快达 250 倍的专用 ufunc。

isfinite 支持 datetime64timedelta64 类型#

以前,当在这些两种类型上使用 isfinite 时,它会引发 TypeError

nan_to_num 添加了新的关键字#

nan_to_num 现在接受关键字 nanposinfneginf,允许用户定义分别替换 nan、正无穷大和负无穷大的值。

由分配过大的数组引起的 MemoryError 描述更加清晰#

MemoryError 的原因通常是不正确的广播,这会导致非常大且不正确的形状。错误消息现在包含此形状,以帮助诊断故障原因。

floorceiltrunc 现在遵守内置魔术方法#

当在对象数组上调用这些 ufunc 时,它们现在会调用 __floor____ceil____trunc__ 方法,使其与 decimal.Decimalfractions.Fraction 对象兼容。

quantile 现在适用于 fraction.Fractiondecimal.Decimal 对象#

通常,这更优雅地处理对象数组,如果使用精确算术类型,则避免浮点运算。

matmul 中支持对象数组#

现在可以使用 matmul(或 @ 运算符)与对象数组。例如,现在可以执行以下操作:

from fractions import Fraction
a = np.array([[Fraction(1, 2), Fraction(1, 3)], [Fraction(1, 3), Fraction(1, 2)]])
b = a @ a

更改#

medianpercentile 函数系列不再发出关于 nan 的警告#

numpy.mediannumpy.percentilenumpy.quantile 以前会在遇到 nan 时发出 RuntimeWarning。由于它们返回 nan 值,因此警告是多余的,已被删除。

调整了timedelta64 % 0的行为,使其返回NaT#

当使用模运算且两个操作数均为np.timedelta64时,如果除数为零,则现在返回NaT,而不是返回零。

NumPy 函数现在始终支持使用__array_function__进行覆盖#

NEP 18中所述,NumPy 现在始终检查__array_function__方法,以实现对非NumPy数组上的NumPy函数的覆盖。此功能在NumPy 1.16中(如果设置了相应的环境变量)可用作测试,但现在始终启用。

lib.recfunctions.structured_to_unstructured不再压缩单字段视图#

之前structured_to_unstructured(arr[['a']])会产生一个压缩的结果,这与structured_to_unstructured(arr[['a', b']])不一致。这是意外的。可以使用structured_to_unstructured(arr[['a']]).squeeze(axis=-1)(或者更简单的arr['a'])来保留旧的行为。

clip现在内部使用ufunc#

这意味着通过descr->f->fastclip在C中为自定义dtype注册clip函数已弃用——它们应该改用ufunc注册机制,附加到np.core.umath.clip ufunc。

这也意味着clip接受wherecasting参数,并且可以使用__array_ufunc__进行覆盖。

此更改的结果是,旧clip的一些行为已被弃用。

  • 传递nan表示“不裁剪”作为上下界之一或两者。无论如何,这在所有情况下都不起作用,可以通过传递适当符号的无穷大来更好地处理。

  • 传递out参数时,默认情况下使用“不安全”转换。显式使用casting="unsafe"将消除此警告。

此外,还有一些行为变化的极端情况。

  • 填充max < min的行为已更改,使其在不同dtype之间更加一致,但不应依赖于此。

  • 标量minmax参与提升规则,就像它们在所有其他ufunc中一样。

__array_interface__偏移量现在按文档说明工作#

该接口可能使用了被错误忽略的offset值。

force zip64标志将savez中的pickle协议设置为3#

savez没有使用force_zip64标志,这将存档大小限制为2GB。但是,使用该标志需要我们使用pickle协议3来写入object数组。使用的协议已升级到3,这意味着Python 2将无法读取该存档。

使用不存在的字段索引结构化数组将引发KeyError而不是ValueError#

在结构化类型上使用arr['bad_field']将引发KeyError,以与dict['bad_field']保持一致。