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
模块,以及四个可选的随机数生成器和改进的种子设计,用于并行进程。当前可用的位生成器是MT19937、PCG64、Philox和SFC64。请参阅下面“新功能”部分。NumPy 的
FFT
实现已从 fftpack 更改为 pocketfft,从而实现了更快、更准确的转换以及对素数长度数据集的更好处理。请参阅下面“改进”部分。新的基数排序和 timsort 排序方法。目前无法选择使用哪一种。它们与数据类型紧密关联,并且在将
stable
或mergesort
作为方法传递时使用。请参阅下面“改进”部分。现在默认情况下可以覆盖 numpy 函数,请参阅下面的
__array_function__
。
新函数#
numpy.errstate
现在也是一个函数装饰器
弃用功能#
numpy.polynomial
函数在传递 float
代替 int
时会发出警告#
以前,此模块中的函数如果提供的是整数型浮点数(1.0
、2.0
等),则会接受 float
值。为了与 NumPy 的其余部分保持一致,现在已弃用此做法,将来会引发 TypeError
。
同样,传递类似 0.5
的浮点数来代替整数现在会引发 TypeError
,而不是之前的 ValueError
。
弃用 numpy.distutils.exec_command
和 temp_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 版本开始,当使用 divmod
和 floor_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), ...)
。
在 take
、choose
、put
中,out
缓冲区用于处理内存重叠#
如果提供了这些函数的 out 参数并且它与其他参数存在内存重叠,则现在对其进行缓冲以避免依赖于顺序的行为。
加载时的解串需要显式选择加入#
load
和 lib.format.read_array
函数接受一个 allow_pickle
关键字参数,现在默认为 False
,以响应 CVE-2019-6446。
旧随机模块中随机流的潜在更改#
由于将 log
应用于随机浮点数的错误,当从 beta
、binomial
、laplace
、logistic
、logseries
或 multinomial
采样时,如果底层 MT19937
随机流中生成了 0
,则流可能会发生变化。发生这种情况的概率为 \(10^{53}\) 分之一,因此对于任何给定的种子,流发生变化的概率极小。如果在底层生成器中遇到 0
,则现在会丢弃产生的错误值(numpy.inf
或 numpy.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
模块,以及四个可选的随机数生成器和改进的种子设计,用于并行进程。当前可用的 位生成器是 MT19937、PCG64、Philox 和 SFC64。PCG64
是新的默认值,而 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 中找到。
packbits
和 unpackbits
接受 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.svd
和 linalg.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.exp
和 numpy.log
的 float32 实现速度提升#
exp
和 log
的 float32 实现现在受益于在运行时检测到的 AVX2/AVX512 指令集。exp
的最大 ulp 误差为 2.52,log
的最大 ulp 误差为 3.83。
提高 numpy.pad
的性能#
通过使用预分配数组填充所需填充形状,而不是使用串联,该函数的性能在大多数情况下得到了提高。
numpy.interp
更稳健地处理无穷大#
对 fromfile
、tofile 和 ndarray.dump
的 Pathlib 支持#
fromfile
、ndarray.ndarray.tofile 和 ndarray.dump
现在支持 pathlib.Path
类型的 file
/fid
参数。
针对 bool 和 int 类型的专用 isnan
、isinf
和 isfinite
ufunc#
isfinite
支持 datetime64
和 timedelta64
类型#
以前,当在这些两种类型上使用 isfinite
时,它会引发 TypeError。
向 nan_to_num
添加了新的关键字#
nan_to_num
现在接受关键字 nan
、posinf
和 neginf
,允许用户定义分别替换 nan
、正无穷大和负无穷大的值。
由分配过大的数组引起的 MemoryError 描述更加清晰#
MemoryError 的原因通常是不正确的广播,这会导致非常大且不正确的形状。错误消息现在包含此形状,以帮助诊断故障原因。
floor
、ceil
和 trunc
现在遵守内置魔术方法#
当在对象数组上调用这些 ufunc 时,它们现在会调用 __floor__
、__ceil__
和 __trunc__
方法,使其与 decimal.Decimal
和 fractions.Fraction
对象兼容。
quantile
现在适用于 fraction.Fraction 和 decimal.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
更改#
median
和 percentile
函数系列不再发出关于 nan
的警告#
numpy.median
、numpy.percentile
和 numpy.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
接受where
和casting
参数,并且可以使用__array_ufunc__
进行覆盖。
此更改的结果是,旧clip
的一些行为已被弃用。
传递
nan
表示“不裁剪”作为上下界之一或两者。无论如何,这在所有情况下都不起作用,可以通过传递适当符号的无穷大来更好地处理。传递
out
参数时,默认情况下使用“不安全”转换。显式使用casting="unsafe"
将消除此警告。
此外,还有一些行为变化的极端情况。
填充
max < min
的行为已更改,使其在不同dtype之间更加一致,但不应依赖于此。标量
min
和max
参与提升规则,就像它们在所有其他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']
保持一致。