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']
保持一致.