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 时会发出警告#
之前此模块中的函数会接受 float 值,只要它们是整数(如 1.0, 2.0 等).为了与 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 数组上调用#
在0维数组上 numpy.nonzero 的行为令人惊讶,几乎总是不正确的.如果旧的行为是故意的,可以通过使用 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``).
未来变化#
在未来的版本中,dtypes 中的 Shape-1 字段不会被折叠为标量.#
目前,指定为 [(name, dtype, 1)] 或 "1type" 的字段被解释为标量字段(即,与 [(name, dtype)] 或 [(name, dtype, ()] 相同).现在会引发一个 FutureWarning;在未来的版本中,它将被解释为形状为 (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 <ma.MaskedArray.mask>` 的行为现在与 data 一致,后者也返回一个视图.
如果需要,仍然可以使用 ._mask 访问底层掩码.包含 assert x.mask is not y.mask 或类似的测试需要更新.
在 numpy.frombuffer 中不要查找 __buffer__ 属性#
在 numpy.frombuffer 中查找 __buffer__ 属性是未记录且非功能的.此代码已被移除.如果需要,请改用 frombuffer(memoryview(obj), ...).
out 在 take, choose, put 中为了内存重叠而被缓冲#
如果这些函数的 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 不再假设所有不安全的转换都是允许的#
之前,`can_cast` 对于几乎所有输入在 casting='unsafe' 时都返回 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 模块,以及四个可选的随机数生成器和改进的种子设定,设计用于并行进程中.目前可用的 Bit Generators 是 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都已实现,现在取代了mergesort.由于需要保持向后兼容性,排序 kind 选项 "stable" 和 "mergesort" 已成为彼此的别名,实际的排序实现取决于数组类型.基数排序用于16位或更小的整数类型,而timsort用于其余类型.Timsort在包含已经或几乎排序的数据上表现更好,并且在随机数据上表现得像mergesort,需要 \(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 参数,与在 1.14.0 中添加到 linalg.matrix_rank 的参数相匹配.
divmod 操作现在支持两个 timedelta64 操作数#
divmod 运算符现在处理两个 timedelta64 操作数,具有类型签名 mm->qm.
fromfile 现在接受一个 offset 参数#
这个函数现在为二进制文件接受一个 offset 关键字参数,该参数指定从文件当前位置开始的偏移量(以字节为单位).默认为 0.
新的模式 “empty” 用于 pad#
此模式将数组填充到所需形状,而不初始化新条目.
浮点标量实现了 as_integer_ratio 以匹配内置的浮点数#
这将返回一个 (分子, 分母) 对,可以用来构造一个 fractions.Fraction.
结构化的 dtype 对象可以用多个字段名称进行索引#
arr.dtype[['a', 'b']] 现在返回一个与 arr[['a', 'b']].dtype 等效的 dtype,以与 arr.dtype['a'] == arr['a'].dtype 保持一致.
像使用字段列表索引的结构化数组的 dtype 一样,这个 dtype 与原始 dtype 具有相同的 itemsize,但只保留字段的一个子集.
这意味着 arr[['a', 'b']] 和 arr.view(arr.dtype[['a', 'b']]) 是等价的.
.npy 文件支持 Unicode 字段名称#
新版本的 3.0 格式已经引入,它支持带有非 latin1 字段名称的结构化类型.这在需要时会自动使用.
改进#
数组比较断言包括最大差异#
数组比较测试(如 testing.assert_allclose)的错误信息现在除了之前的”不匹配”百分比外,还包括”最大绝对差异”和”最大相对差异”.这些信息使得更新绝对和相对误差容限变得更加容易.
将基于 fftpack 的 fft 模块替换为 pocketfft 库#
两种实现都有相同的祖先(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 实现的加速#
float32 实现的 exp 和 log 现在可以从 AVX2/AVX512 指令集受益,这些指令集在运行时被检测到.`exp` 的最大 ulp 误差为 2.52,而 log 的最大 ulp 误差为 3.83.
提高 numpy.pad 的性能#
通过使用预分配数组填充所需填充形状而不是使用连接,该函数的性能在大多数情况下得到了改进.
numpy.interp 更稳健地处理无穷大#
在某些情况下,`interp` 以前会返回 nan,现在它会返回适当的无穷大.
Pathlib 支持 fromfile、tofile 和 ndarray.dump#
fromfile, ndarray.ndarray.tofile 和 ndarray.dump 现在支持 pathlib.Path 类型作为 file/fid 参数.
专门用于布尔和整数类型的 isnan, isinf, 和 isfinite ufuncs#
布尔和整数类型无法存储 nan 和 inf 值,这使我们能够提供专门的 ufuncs,其速度比以前的方法快 250 倍.
isfinite 支持 datetime64 和 timedelta64 类型#
之前,`isfinite` 在用于这两种类型时会引发 TypeError.
新增的关键字到 nan_to_num#
nan_to_num 现在接受关键字 nan、posinf 和 neginf,允许用户分别定义替换 nan、正负 np.inf 值的值.
由于分配了过大的数组而导致的 MemoryErrors 更具描述性#
通常,MemoryError 的原因是不正确的广播,这会导致一个非常大且不正确的形状.现在,错误信息中包含了此形状,以帮助诊断失败的原因.
floor, ceil, 和 trunc 现在尊重内置的魔法方法#
这些ufuncs现在在对象数组上调用时会调用 __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__ 进行重写#
现在,NumPy 总是检查 __array_function__ 方法,以在非 NumPy 数组上实现对 NumPy 函数的重写,如 NEP 18 中所述.如果设置了适当的环境变量,该功能在 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 中为自定义 dtypes 注册 clip 函数已被弃用 - 它们应改为使用 ufunc 注册机制,附加到 np.core.umath.clip ufunc.
这也意味着 clip 接受 where 和 casting 参数,并且可以用 __array_ufunc__ 重写.
这一变化的一个后果是,旧的 clip 的一些行为已被弃用:
传递
nan表示”不剪切”作为一个或两个边界.无论如何,这在所有情况下都不起作用,并且可以通过传递适当符号的无穷大来更好地处理.当传递一个
out参数时,默认使用”不安全”的转换.显式使用casting="unsafe"将静默此警告.
此外,还有一些行为变化的小众情况:
填充
max < min的行为在不同数据类型间变得更加一致,但不应依赖于此.标量
min和max像在所有其他 ufuncs 中一样参与提升规则.
__array_interface__ 偏移现在按照文档工作#
该接口可能使用了被错误忽略的 offset 值.
在 savez 中的 Pickle 协议设置为 3,用于 force zip64 标志#
savez 没有使用 force_zip64 标志,这限制了存档的大小为2GB.但使用该标志需要我们使用 pickle 协议 3 来写入 object 数组.协议已升级到3,这意味着存档将无法被 Python2 读取.
使用不存在的字段索引结构化数组会引发 KeyError 而不是 ValueError#
在结构化类型上调用 arr['bad_field'] 会引发 KeyError,以与 dict['bad_field'] 保持一致.