NumPy 1.14.0 发行说明#
NumPy 1.14.0 是七个月工作的成果,包含大量错误修复和新功能,以及一些可能存在兼容性问题的更改。用户会注意到的主要更改是 NumPy 数组和标量打印方式的风格变化,这一变化将影响 doctest。有关如何在需要时保留旧式打印的详细信息,请参阅下文。
一项影响未来开发的重要决定涉及在 2020 年前逐步停止对 Python 2.7 支持的时间表。目前已决定在 2018 年发布的所有版本中支持 2.7,其中最后一个版本将指定为长期版本,其错误修复支持将延长至 2019 年。2019 年,所有新版本都将停止对 2.7 的支持。更多详情可在 NEP 12 中找到。
此版本支持 Python 2.7 和 3.4 - 3.6。
亮点#
np.einsum 函数在可能时使用 BLAS
genfromtxt、loadtxt、fromregex和savetxt现在可以处理具有任意 Python 支持编码的文件。NumPy 数组和标量打印方面的重大改进。
新增函数#
parametrize:装饰器已添加到 numpy.testingchebinterpolate:在切比雪夫点处插值函数。format_float_positional和format_float_scientific:明确格式化浮点标量,并控制舍入和填充。PyArray_ResolveWritebackIfCopy和PyArray_SetWritebackIfCopyBase,新的 C-API 函数,有助于实现 PyPy 兼容性。
弃用#
弃用使用
np.bool_对象代替整数。以前operator.index(np.bool_)是合法的,并允许诸如[1, 2, 3][np.True_]这样的构造。这具有误导性,因为它与np.array([1, 2, 3])[np.True_]的行为不同。弃用对空数组进行真值测试。要检查数组是否不为空,请使用
array.size > 0。弃用调用
np.bincount时使用minlength=None。应改为使用minlength=0。弃用调用
np.fromstring时使用sep参数的默认值。当未提供此参数时,会使用一个损坏的np.frombuffer版本,该版本默默接受 Unicode 字符串,并在将其编码为 utf-8 (Python 3) 或默认编码 (Python 2) 后,将其视为二进制数据。如果需要读取二进制数据,应直接使用np.frombuffer。在非旧版打印模式下,`array2string` 的
style选项已弃用。PyArray_SetUpdateIfCopyBase已弃用。对于 NumPy 版本 >= 1.14,请改用PyArray_SetWritebackIfCopyBase,更多详情请参阅下面的C API 变更。弃用使用
UPDATEIFCOPY数组,详情请参阅下面的C API 变更。我们不会停止对这些数组的支持,但它们与 PyPy 不兼容。
未来变更#
np.issubdtype将停止降级类似 dtype 的参数。可能期望issubdtype(np.float32, 'float64')和issubdtype(np.float32, np.float64)含义相同 — 然而,之前存在一个未文档化的特殊情况,将前者转换为issubdtype(np.float32, np.floating),从而给出令人惊讶的 True 结果。此转换现在会发出警告,解释正在进行的转换。将来,此转换将被禁用,第一个示例将与第二个示例等效。
np.linalg.lstsq的rcond默认值将更改。np.linalg.lstsq的rcond参数的默认值将更改为机器精度乘以输入数组维度的最大值。当未明确传递rcond时,会发出 `FutureWarning`。当
a为非连续时,a.flat.__array__()将返回a的可写副本。以前,当a可写时,它会返回一个 `UPDATEIFCOPY` 数组。目前它返回一个不可写副本。有关该问题的讨论,请参阅 gh-7054。非结构化 void 数组的
.item方法将返回一个 `bytes` 对象。将来,对np.void数据类型的数组或标量调用.item()将返回一个bytes对象,而不是缓冲区或整数数组,这与bytes(void_scalar)返回的相同。这可能会影响假设返回值可变的代码,未来将不再如此。现在当发生这种情况时会发出 `FutureWarning`。
兼容性说明#
掩码数组视图的掩码也是视图而非副本#
NumPy 1.11.x 中关于此更改有一个 `FutureWarning`。简而言之,现在更改掩码数组的视图时,对掩码的更改会传播到原始数组。以前并非如此。此更改尤其影响切片。请注意,如果原始数组的掩码是 nomask 且视图的掩码已更改,则此功能目前无法正常工作。有关更详细的讨论,请参阅 gh-5580。可以通过调用视图的 unshare_mask 方法来获得保留掩码副本的原始行为。
np.ma.masked 不再可写#
尝试修改 masked 常量现在会出错,因为底层数组已标记为只读。过去,可以通过以下方式做到:
# emulating a function that sometimes returns np.ma.masked
val = random.choice([np.ma.masked, 10])
var_arr = np.asarray(val)
val_arr += 1 # now errors, previously changed np.ma.masked.data
np.ma 生成 fill_value 的函数已更改#
以前,np.ma.default_fill_value 会返回一个 0 维数组,而 np.ma.minimum_fill_value 和 np.ma.maximum_fill_value 会返回一个字段元组。现在,所有这三个方法都返回一个结构化的 np.void 对象,这与您已在 .fill_value 属性中找到的内容相同。
此外,dtype 猜测现在与 np.array 的猜测匹配 — 因此,当传递 Python 标量 x 时,maximum_fill_value(x) 总是与 maximum_fill_value(np.array(x)) 相同。以前在 Python 2 上 x = long(1) 违反了这一假设。
当 a 为非连续时,a.flat.__array__() 返回不可写数组#
其目的是将来将 `UPDATEIFCOPY` 数组(以前在 `a` 非连续时返回)替换为可写副本。这项临时措施旨在通知那些期望在这种情况下修改底层数组的人,这种情况将不再发生。最有可能注意到这一点的地方是使用 np.asarray(a.flat) 形式的表达式,或者当 `a.flat` 作为 ufunc 的 `out` 参数传递时。
当对 0 长度维度收缩时,np.tensordot 现在返回零数组#
以前,当对 0 长度维度收缩时,np.tensordot 会引发 `ValueError`。现在它返回一个零数组,这与 np.dot 和 np.einsum 的行为一致。
numpy.testing 已重组#
预计这不会导致问题,但可能遗漏了一些东西。如果您在使用 numpy.testing 时遇到意外的导入问题,请告诉我们。
np.asfarray 不再通过 dtype 参数接受非 dtype#
以前,这会接受 dtype=some_array,并暗示语义为 dtype=some_array.dtype。这没有文档记录,在 NumPy 函数中是独一无二的,如果使用,很可能对应于拼写错误。
1D np.linalg.norm 保留浮点输入类型,即使对于任意阶数#
以前,当传递任意阶数时,这会提升为 float64,尽管在简单情况下不会这样做。
>>> f32 = np.float32([[1, 2]])
>>> np.linalg.norm(f32, 2.0, axis=-1).dtype
dtype('float32')
>>> np.linalg.norm(f32, 2.0001, axis=-1).dtype
dtype('float64') # numpy 1.13
dtype('float32') # numpy 1.14
此更改仅影响 float32 和 float16 数组。
count_nonzero(arr, axis=()) 现在计算零轴而不是所有轴#
在其他地方,axis==() 总是被理解为“无轴”,但 count_nonzero 有一个特殊情况,将其视为“所有轴”。这不一致且令人惊讶。计算所有轴的正确方法始终是传递 axis == None。
__init__.py 文件已添加到测试目录#
这是为了在不同目录中存在重复测试文件名的情况下与 pytest 兼容。因此,run_module_suite 不再工作,即 python <path-to-test-file> 会导致错误。
对非结构化 void 数组执行 .astype(bool) 现在对每个元素调用 bool#
在 Python 2 中,void_array.astype(bool) 总是返回一个 True 数组,除非 dtype 是 V0。在 Python 3 中,此操作通常会崩溃。将来,astype 将匹配 bool(np.void) 的行为,将全零缓冲区视为 False,其他任何值视为 True。仍然可以使用 arr.dtype.itemsize == 0 检查 V0。
MaskedArray.squeeze 从不返回 np.ma.masked#
np.squeeze 文档中说明它返回一个视图,但掩码变体有时会返回 masked,它不是视图。此问题已修复,因此结果始终是原始掩码数组的视图。这会破坏任何使用 masked_arr.squeeze() is np.ma.masked 的代码,但会修复写入 squeeze() 结果的代码。
将 can_cast 的第一个参数从 from 重命名为 from_#
以前的参数名 from 是 Python 中的保留关键字,这使得按名称传递参数变得困难。通过将参数重命名为 from_ 来解决此问题。
传递错误类型时,isnat 引发 TypeError#
当未传递 datetime 或 timedelta 类型的变量时,ufunc isnat 曾经引发 `ValueError`。现在已更改为引发 `TypeError`。
传递错误类型时,dtype.__getitem__ 引发 TypeError#
当使用浮点数进行索引时,dtype 对象曾经引发 `ValueError`。
用户定义类型现在需要实现 __str__ 和 __repr__#
以前,用户定义类型可以回退到 NumPy 中实现的 __str__ 和 __repr__ 的默认实现,但现在已将其删除。现在,用户定义类型将回退到 Python 默认的 object.__str__ 和 object.__repr__。
数组打印的许多更改,可通过新的“旧版”打印模式禁用#
ndarray 和 NumPy 标量的 str 和 repr 已以多种方式更改。这些更改可能会破坏下游用户的 doctest。
通过启用新的 1.13 “旧版”打印模式,可以禁用这些新行为,以在很大程度上重现 NumPy 1.13 的行为。可以通过调用 np.set_printoptions(legacy="1.13"),或使用 np.array2string 的新 legacy 参数(例如 np.array2string(arr, legacy='1.13'))来启用此模式。
总而言之,主要更改如下:
对于浮点类型
浮点数组的
repr通常会省略以前在符号位置打印的空格。请参阅np.set_printoptions的新sign选项。浮点数组和标量使用新的算法进行十进制表示,给出最短的唯一表示。这通常会缩短
float16的小数输出,有时也会缩短float32和float128的输出。float64应该不受影响。请参阅np.set_printoptions的新floatmode选项。以科学记数法打印的浮点数组不再使用固定精度,而是显示最短的唯一表示。
在 Python 2 中,浮点标量的
str不再被截断。
对于其他数据类型
非有限复数标量打印为
nanj而不是nan*j。datetime 数组中的
NaT值现在已正确对齐。类型为
np.void的数组和标量现在以十六进制表示法打印。
对于换行
如果数组输出的最后一行没有空间,ndarray reprs 的“dtype”部分现在将在下一行打印。
linewidth格式选项现在始终受到尊重。数组的 repr 或 str 永远不会超过此值,除非单个元素过宽。数组字符串的最后一行元素永远不会比前面的行多。
如果元素太宽,第一行不再插入额外的空格。
对于摘要(使用
...缩短长数组)str不再插入尾随逗号。以前,str(np.arange(1001))返回'[ 0 1 2 ..., 998 999 1000]',其中包含一个额外的逗号。对于 2D 及以上维度的数组,当
...在其自身行上打印以总结除最后一轴以外的任何轴时,现在会在该行后追加换行符以匹配其前导换行符,并删除尾随空格字符。
MaskedArray数组现在用逗号分隔打印的元素,总是打印 dtype,并正确地将长数组的元素换行到多行。如果维度多于 1,则数组属性现在以新的“左对齐”打印样式打印。recarray数组在它们的 dtype 之前不再打印尾随空格,并正确地换行到正确的列数。0 维数组不再拥有自己特殊的
str和repr实现。np.array2string的style参数已弃用。bool数据类型的数组将在repr中省略数据类型。用户定义 dtype(
np.generic的子类)现在需要实现__str__和__repr__。
其中一些更改将在下面详细描述。如果出于 doctest 或其他原因需要保留以前的行为,您可能需要执行以下操作:
# FIXME: We need the str/repr formatting used in Numpy < 1.14.
try:
np.set_printoptions(legacy='1.13')
except TypeError:
pass
C API 变更#
`UPDATEIFCOPY` 数组的 PyPy 兼容替代方案#
UPDATEIFCOPY 数组是现有数组的连续副本,可能具有不同的维度,当它们的引用计数降至零并被解除分配时,其内容将被复制回原始数组。由于 PyPy 不使用引用计数,因此它们与 PyPy 无法正常工作。NumPy 正在内部消除它们的使用,并且已添加两个新的 C-API 函数:
PyArray_SetWritebackIfCopyBasePyArray_ResolveWritebackIfCopy,
以及一个补充标志 NPY_ARRAY_WRITEBACKIFCOPY。使用新功能还要求在创建新数组时更改一些标志,即:NPY_ARRAY_INOUT_ARRAY 应替换为 NPY_ARRAY_INOUT_ARRAY2,NPY_ARRAY_INOUT_FARRAY 应替换为 NPY_ARRAY_INOUT_FARRAY2。使用这些新标志创建的数组将具有 WRITEBACKIFCOPY 语义。
如果 PyPy 兼容性不是问题,可以忽略这些新函数,尽管会收到 `DeprecationWarning`。如果您确实希望实现 PyPy 兼容性,有关这些函数及其使用的更多信息可以在 c-api 文档和 how-to-extend 中的示例中找到。
新特性#
文本 IO 函数的编码参数#
genfromtxt、loadtxt、fromregex 和 savetxt 现在可以通过编码参数处理具有 Python 支持的任意编码的文件。为了向后兼容,该参数默认为特殊的 bytes 值,该值继续将文本视为原始字节值,并继续将 latin1 编码的字节传递给自定义转换器。使用任何其他值(包括 `None` 表示系统默认值)将使函数切换到真实的文本 IO,从而在结果数组中接收 Unicode 字符串而不是字节。
外部 `nose` 插件可由 numpy.testing.Tester 使用#
numpy.testing.Tester 现在能够识别 nose 内置插件之外的 `nose` 插件。这允许例如使用 nose-timer,如下所示:np.test(extra_argv=['--with-timer', '--timer-top-n', '20']) 以获取 20 个最慢测试的运行时。一个额外的关键字 timer 也已添加到 Tester.test,因此 np.test(timer=20) 也会报告 20 个最慢的测试。
parametrize 装饰器已添加到 numpy.testing#
numpy.testing 中现在提供了一个基本的 parametrize 装饰器。它旨在允许重写在 pytest 中已弃用的基于 yield 的测试,以方便将来过渡到 pytest。nose 测试框架已经多年未受支持,看起来像是弃用软件。
新的 parametrize 装饰器不具备 pytest 中装饰器的全部功能。它不适用于类,不支持嵌套,也不替换变量名。即便如此,它也应该足以重写 NumPy 测试。
chebinterpolate 函数已添加到 numpy.polynomial.chebyshev#
新的 chebinterpolate 函数在第一类切比雪夫点处插值给定函数。Chebyshev.interpolate 类方法增加了对使用缩放和移动的第一类切比雪夫点在任意区间上进行插值的支持。
Python 3 中支持读取 lzma 压缩文本文件#
在包含 lzma 模块的 Python 版本中,文本 IO 函数现在可以透明地读取带有 xz 或 lzma 扩展名的文件。
sign 选项已添加到 np.setprintoptions 和 np.array2string#
此选项控制浮点类型的符号打印,可以是字符 '-'、'+' 或 ' ' 之一。使用 '+' 时,NumPy 总是打印正值的符号;使用 ' ' 时,它总是在正值的符号位置打印一个空格(空白字符);使用 '-' 时,它将省略正值的符号字符。新的默认值是 '-'。
此新默认值相对于 NumPy 1.13 更改了浮点输出。旧行为可以在 1.13 “旧版”打印模式中获得,请参阅上面的兼容性说明。
hermitian 选项已添加到 np.linalg.matrix_rank#
新的 hermitian 选项允许在标准基于 SVD 的矩阵秩计算和针对对称/厄米特矩阵的更高效的基于特征值的方法之间进行选择。
threshold 和 edgeitems 选项已添加到 np.array2string#
这些选项以前可以通过 np.set_printoptions 控制,但现在可以作为 np.array2string 的参数按每次调用进行更改。
concatenate 和 stack 增加了 out 参数#
现在可以将所需 dtype 的预分配缓冲区用于这些函数的输出。
Windows 上对 PGI flang 编译器的支持#
PGI flang 编译器是 NVIDIA 在 Apache 2 许可下发布的 LLVM 的 Fortran 前端。它可以通过以下方式调用:
python setup.py config --compiler=clang --fcompiler=flang install
这种新编译器的使用经验很少,因此欢迎用户提供任何反馈。
改进#
random.noncentral_f 中的分子自由度只需为正。#
在 NumPy 1.14.0 之前,分子自由度需要 > 1,但分布对 > 0 的值有效,这是新要求。
所有 np.einsum 变体都已释放 GIL#
在 NumPy 1.14.0 之前,某些具有加速循环版本的特定循环结构未释放 GIL。此疏忽已得到修复。
np.einsum 函数在可能时将使用 BLAS 并默认优化#
np.einsum 函数现在将在适当时调用 np.tensordot。由于 np.tensordot 在可能时使用 BLAS,这将加快执行速度。默认情况下,np.einsum 还会尝试优化,因为与潜在的速度改进相比,开销很小。
f2py 现在处理维度为 0 的数组#
f2py 现在允许分配维度为 0 的数组。这使得下游对边缘情况的处理更加一致。
numpy.distutils 支持同时使用 MSVC 和 mingw64-gfortran#
Numpy distutils 现在支持同时使用 Mingw64 gfortran 和 MSVC 编译器。这使得在 Windows 上生成包含 Fortran 代码的 Python 扩展模块成为可能,同时保留与 Python.org 分发的二进制文件的兼容性。并非所有用例都受支持,但大多数常见的 Fortran 包装方式都是可用的。
此模式下的编译通常会自动启用,可以通过 setup.py 的 --fcompiler 和 --compiler 选项进行选择。此外,支持将 Fortran 代码链接到静态 OpenBLAS;默认情况下会查找 gfortran 兼容的静态归档文件 openblas.a。
np.linalg.pinv 现在适用于堆叠矩阵#
以前它仅限于单个 2D 数组。
numpy.save 将数据对齐到 64 字节而不是 16 字节#
使用 numpy.save 将 NumPy 数组保存为 npy 格式时,会在数组数据之前插入填充,以将其对齐到 64 字节。以前这只有 16 字节(由于版本 2 代码中的一个错误,有时甚至更少)。现在对齐方式为 64 字节,这与常用最宽的 SIMD 指令集匹配,也是最常见的缓存行大小。这使得 npy 文件在通过 mmap 打开它们的程序中更容易使用,尤其是在 Linux 上,其中 mmap 偏移量必须是页面大小的倍数。
NPZ 文件现在可以在不使用临时文件的情况下写入#
在 Python 3.6+ 中,numpy.savez 和 numpy.savez_compressed 现在直接写入 ZIP 文件,而无需创建中间临时文件。
更好地支持空结构化和字符串类型#
结构化类型可以包含零个字段,字符串 dtype 可以包含零个字符。零长度字符串仍然无法直接创建,必须通过结构化 dtype 构造。
str0 = np.empty(10, np.dtype([('v', str, N)]))['v']
void0 = np.empty(10, np.void)
以前总是可以处理这些,但现在支持这些数组的以下操作:
arr.sort()
arr.view(bytes)
arr.resize(…)
pickle.dumps(arr)
np.lib.financial 中对 decimal.Decimal 的支持#
除非另有说明,否则 financial 包中的所有函数现在都支持使用内置的 decimal.Decimal 类型。
浮点打印现在使用“dragon4”算法以获得最短十进制表示#
浮点值(16、32、64 和 128 位)的 str 和 repr 现在打印为最短的十进制表示,该表示唯一标识该值与同一类型的其他值。以前这仅适用于 float64 值。其余浮点类型现在通常比 NumPy 1.13 中的更短。以科学记数法打印的数组现在也使用最短的科学表示法,而不是像以前那样的固定精度。
此外,浮点标量的 str 在 Python 2 中将不再被截断,这与 Python 2 的 float 不同。np.double 标量的
str和repr现在与 Python 3 浮点数的相同。
提供了新函数 np.format_float_scientific 和 np.format_float_positional 来生成这些十进制表示。
np.set_printoptions 和 np.array2string 中新增了一个 floatmode 选项,它控制数组中打印元素的唯一性和舍入。新的默认值是 floatmode='maxprec',精度为 8,这将打印最多 8 位小数,如果元素可以用更少的位数唯一表示,则打印更少。一个有用的新模式是 floatmode="unique",它将输出足够的位数来唯一指定数组元素。
值如 inf*j 或 nan*j 的 NumPy 复浮点标量现在打印为 infj 和 nanj,就像纯 Python 的 complex 类型一样。
FloatFormat 和 LongFloatFormat 类已弃用,应替换为 FloatingFormat。同样,ComplexFormat 和 LongComplexFormat 应替换为 ComplexFloatingFormat。
void 数据类型元素现在以十六进制表示法打印#
现在,非结构化 np.void 元素(例如 V4 数据类型)打印为与 Python bytes 类型兼容的十六进制表示。以前,在 Python 2 中,元素的原始 void 数据会打印到标准输出;在 Python 3 中,会显示整数字节值。
void 数据类型的打印样式现在可以独立自定义#
np.void 数组的打印样式现在可以使用 np.set_printoptions 的 formatter 参数独立自定义,使用 'void' 键,而不是以前的通用 numpystr 键。
np.loadtxt 的内存使用量减少#
np.loadtxt 现在分块读取文件而不是一次性读取,这大大减少了大型文件的内存使用量。
变更#
结构化数组的多字段索引/赋值#
结构化数组的多字段索引和赋值已发生多方面更改,如先前版本中警告所示。
首先,使用多个字段索引结构化数组,例如 arr[['f1', 'f3']],返回原始数组的视图而不是副本。返回的视图将包含与原始数组中介入字段对应的额外填充字节,与 1.13 中的副本不同,这将影响诸如 arr[['f1', 'f3']].view(newdtype) 等代码。
其次,结构化数组之间的赋值现在将“按位置”发生,而不是“按字段名”发生。目标的第 N 个字段将被设置为源的第 N 个字段,无论字段名如何,这与 NumPy 1.6 到 1.13 版本中目标数组中的字段被设置为源数组中同名字段或 0(如果源没有该字段)不同。
相应地,在计算 dtype 相等性时,结构化 dtypes 中字段的顺序现在变得重要。例如,对于 dtypes:
x = dtype({'names': ['A', 'B'], 'formats': ['i4', 'f4'], 'offsets': [0, 4]})
y = dtype({'names': ['B', 'A'], 'formats': ['f4', 'i4'], 'offsets': [4, 0]})
表达式 x == y 现在将返回 False,这与以前不同。这使得在 Python < 3.6 中基于字典的 dtype 规范(如 dtype({'a': ('i4', 0), 'b': ('f4', 4)}))变得危险,因为这些版本不保留字典键顺序。
从结构化数组赋值到布尔数组现在引发 `ValueError`,这与 1.13 中始终将目标元素设置为 `True` 不同。
从具有多个字段的结构化数组赋值到非结构化数组现在引发 `ValueError`。在 1.13 中,这仅将源的第一个字段复制到目标。
现在禁止在多字段索引中使用字段“titles”,也禁止在多字段索引中重复字段名。
用户指南中结构化数组的文档已显著更新以反映这些更改。
整数和 Void 标量现在不受 np.set_string_function 的影响#
以前,与大多数其他 NumPy 标量不同,整数和 void 标量的 str 和 repr 可以通过 np.set_string_function 控制。现在这不再可能。
0维数组打印已更改,array2string 的 style 参数已弃用#
以前,0 维数组的 str 和 repr 具有特殊的实现,对于 0 维数组 a,它们分别返回 str(a.item()) 和 'array(' + repr(a.item()) + ')',这与 NumPy 标量和高维 ndarray 都不同。
现在,0 维数组的 str 行为类似于使用 str(a[()]) 的 NumPy 标量,而 repr 行为类似于使用 formatter(a[()]) 的高维数组,其中 formatter 可以通过 np.set_printoptions 指定。np.array2string 的 style 参数已弃用。
此新行为在 1.13 旧版打印模式中被禁用,请参阅上面的兼容性说明。
使用数组播种 RandomState 需要一个 1 维数组#
RandomState 以前会接受空数组或具有 2 个或更多维度的数组,这导致要么播种失败(空数组),要么在设置种子时忽略某些传递的值。
MaskedArray 对象显示更有用的 repr#
MaskedArray 的 repr 现在更接近于生成它的 Python 代码,数组现在显示逗号和 dtype。像其他格式更改一样,可以通过 1.13 旧版打印模式禁用此功能,以帮助过渡 doctest。
np.polynomial 类的 repr 更明确#
它现在将域和窗口参数显示为关键字参数,使其更清晰。
>>> np.polynomial.Polynomial(range(4))
Polynomial([0., 1., 2., 3.], domain=[-1, 1], window=[-1, 1])