NumPy 1.14.0 发布说明#

Numpy 1.14.0 是七个月工作的成果,包含了大量的错误修复和新功能,以及一些可能存在兼容性问题的更改。用户最明显的变化是 numpy 数组和标量打印方式的风格变化,这将影响 doctests。关于如何在需要时保留旧的打印风格的详细信息,请参见下文。

一项影响未来开发的重要决策是关于在 2020 年前逐步停止支持 Python 2.7 的计划。已决定在 2018 年的所有发布版本中支持 2.7,最后一个版本将被指定为长期支持版本,bug 修复支持将延长至 2019 年。2019 年,所有新发布版本将停止支持 2.7。更多细节可在 NEP 12 中找到。

此版本支持 Python 2.7 和 3.4 - 3.6。

亮点#

  • 在可能的情况下,np.einsum 函数将使用 BLAS。

  • genfromtxtloadtxtfromregexsavetxt 现在可以处理具有 Python 支持的任意编码的文件。

  • 对 NumPy 数组和标量的打印进行了重大改进。

新增函数#

  • parametrize:在 numpy.testing 中添加了装饰器。

  • chebinterpolate:在 Chebyshev 点插值函数。

  • format_float_positionalformat_float_scientific:通过控制舍入和填充来无歧义地格式化浮点标量。

  • PyArray_ResolveWritebackIfCopyPyArray_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

  • 使用 minlength=None 调用 np.bincount 已弃用。应改用 minlength=0

  • 使用 sep 参数的默认值调用 np.fromstring 已弃用。当未提供该参数时,将使用 np.frombuffer 的一个损坏版本,该版本会默默接受 unicode 字符串,并在(python 3 中将其编码为 utf-8,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.lstsqrcond 默认值将更改。np.linalg.lstsqrcond 参数的默认值将更改为机器精度乘以输入数组维度的最大值。当未显式传递 rcond 时,会发出 FutureWarning。

  • a.flat.__array__()a 非连续时将返回一个可写副本。以前,当 a 可写时,它会返回一个 UPDATEIFCOPY 数组。目前它返回一个不可写副本。有关此问题的讨论,请参见 gh-7054。

  • 非结构化 void 数组的 .item 方法将返回一个 bytes 对象。将来,对 np.void 数据类型的数组或标量调用 .item() 将返回一个 bytes 对象,而不是 buffer 或 int 数组,这与 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 会返回一个 0d 数组,但 np.ma.minimum_fill_valuenp.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.flat.__array__()a 非连续时返回不可写数组#

目的是,以前在 a 非连续时返回的 UPDATEIFCOPY 数组将在未来被一个可写副本取代。这一临时措施旨在通知那些期望在此情况下修改底层数组的人,这种情况将不再发生。最有可能注意到这一点的地方是使用 np.asarray(a.flat) 形式的表达式,或者当 a.flat 作为 ufunc 的 out 参数传递时。

np.tensordot 现在在收缩 0 长度维度时返回零数组#

以前 np.tensordot 在收缩 0 长度维度时会引发 ValueError。现在它返回一个零数组,这与 np.dotnp.einsum 的行为一致。

numpy.testing 重组#

这预计不会引起问题,但可能有所遗漏。如果您在使用 numpy.testing 时遇到意外的导入问题,请告知我们。

np.asfarray 不再通过 dtype 参数接受非 dtypes#

以前,这会接受 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

此更改仅影响 float32float16 数组。

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#

ufunc isnat 以前在未传递 datetimetimedelta 类型变量时会引发 ValueError。这已更改为引发 TypeError

dtype.__getitem__ 在传递错误类型时引发 TypeError#

当使用浮点数进行索引时,dtype 对象以前会引发 ValueError

用户定义的类型现在需要实现 __str____repr__#

以前,用户定义的类型可以回退到 numpy 中实现的 __str____repr__ 的默认实现,但现在已移除。现在用户定义的类型将回退到 python 的默认 object.__str__object.__repr__

数组打印的许多更改,可以通过新的“遗留”打印模式禁用#

ndarray 和 numpy 标量的 strrepr 已以多种方式更改。这些更改很可能会破坏下游用户的 doctests。

可以通过调用 np.set_printoptions(legacy="1.13"),或使用 np.array2string 的新 legacy 参数(例如 np.array2string(arr, legacy='1.13'))来启用新的 1.13 “遗留”打印模式,从而禁用这些新行为以在很大程度上重现 numpy 1.13 的行为。

总而言之,主要的更改是

  • 对于浮点类型

    • 浮点数组的 repr 通常会省略先前在符号位置打印的一个空格。请参见 np.set_printoptions 的新 sign 选项。

    • 浮点数组和标量使用新的十进制表示算法,给出最短的唯一表示。这通常会缩短 float16 的小数输出,有时也会缩短 float32float128 的输出。 float64 应不受影响。请参见 np.set_printoptions 的新 floatmode 选项。

    • 以科学记数法打印的浮点数组不再使用固定精度,而是显示最短的唯一表示。

    • 浮点标量的 str 在 python2 中不再被截断。

  • 对于其他数据类型

    • 非有限复数标量打印为 nanj 而不是 nan*j

    • NaT 值在 datetime 数组中现在会正确对齐。

    • np.void 数据类型的数组和标量现在使用十六进制表示法打印。

  • 对于换行

    • 如果 ndarray repr 的“dtype”部分在数组输出的最后一行没有空间,它现在将被打印到下一行。

    • linewidth 格式选项现在始终被遵守。数组的 reprstr 永远不会超过此宽度,除非单个元素太宽。

    • 数组字符串的最后一行永远不会比前几行包含更多的元素。

    • 如果元素太宽,第一行不再插入额外的空格。

  • 对于摘要(使用 ... 来缩短长数组)

    • 对于 str,不再插入尾随逗号。以前,str(np.arange(1001)) 会给出 '[   0    1    2 ...,  998  999 1000]',其中有一个额外的逗号。

    • 对于 2 维及以上的数组,当 ... 被打印在单独一行以总结除最后轴以外的所有轴时,现在会在该行附加换行符以匹配其开头的换行符,并删除尾随空格字符。

  • MaskedArray 数组现在使用逗号分隔打印的元素,始终打印 dtype,并正确地将长数组的元素换行到多行。如果维度大于 1,数组属性现在以新的“左对齐”打印样式打印。

  • recarray 数组不再在其 dtype 前打印尾随空格,并能正确换行到适当的列数。

  • 0d 数组不再拥有自己特有的 strrepr 实现。np.array2stringstyle 参数已弃用。

  • 布尔(bool)数据类型的数组将在 repr 中省略数据类型。

  • 用户定义的 dtypesnp.generic 的子类)现在需要实现 __str____repr__

其中一些更改将在下面更详细地描述。如果您需要保留以前的行为以进行 doctests 或其他原因,您可能需要执行类似以下的操作:

# 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_SetWritebackIfCopyBase

  • PyArray_ResolveWritebackIfCopy,

以及一个补充标志 NPY_ARRAY_WRITEBACKIFCOPY。使用新功能还需要在创建新数组时更改某些标志,即:NPY_ARRAY_INOUT_ARRAY 应被替换为 NPY_ARRAY_INOUT_ARRAY2NPY_ARRAY_INOUT_FARRAY 应被替换为 NPY_ARRAY_INOUT_FARRAY2。使用这些新标志创建的数组将具有 WRITEBACKIFCOPY 语义。

如果 PyPy 兼容性不是问题,可以忽略这些新函数,尽管会有 DeprecationWarning。如果您确实希望实现 PyPy 兼容性,可以在 c-api 文档和 how-to-extend 中的示例中找到有关这些函数及其用法的更多信息。

新功能#

文本 IO 函数的 encoding 参数#

genfromtxtloadtxtfromregexsavetxt 现在可以通过 encoding 参数处理支持 Python 的任意编码的文件。为向后兼容,该参数默认为特殊的 bytes 值,该值继续将文本视为原始字节值,并继续将 latin1 编码的字节传递给自定义转换器。使用任何其他值(包括 None 表示系统默认值)会将函数切换到真正的文本 IO,这样在结果数组中就会收到 unicode 字符串而不是字节。

numpy.testing.Tester 可使用外部 nose 插件#

numpy.testing.Tester 现在可以识别 nose 插件(这些插件不在 nose 内置插件之外)。这允许使用例如 nose-timer,如下所示: np.test(extra_argv=['--with-timer', '--timer-top-n', '20']) 以获取 20 个最慢测试的运行时间。Tester.test 还添加了一个额外的关键字参数 timer,因此 np.test(timer=20) 也会报告 20 个最慢的测试。

numpy.testing 中添加了 parametrize 装饰器#

NumPy 的 numpy.testing 中现在提供了一个基本的 parametrize 装饰器。它旨在允许重写 pytest 中已弃用的 yield 方式的测试,以方便将来迁移到 pytest。nose 测试框架已弃用多年,看起来像是被放弃的软件。

新的 parametrize 装饰器不具备 pytest 中装饰器的全部功能。它不适用于类,不支持嵌套,也不替换变量名。即便如此,它也应该足够用于重写 NumPy 的测试。

numpy.polynomial.chebyshev 中添加了 chebinterpolate 函数#

新的 chebinterpolate 函数在第一类 Chebyshev 点上对给定函数进行插值。一个新的 Chebyshev.interpolate 类方法通过第一类 Chebyshev 点的缩放和移位来支持任意区间的插值。

Python 3 中支持读取 lzma 压缩的文本文件#

对于包含 lzma 模块的 Python 版本,文本 IO 函数现在可以透明地读取扩展名为 xzlzma 的文件。

np.setprintoptionsnp.array2string 中添加了 sign 选项#

此选项控制浮点类型符号的打印,可以是字符‘-’、‘+’或‘ ’之一。使用‘+’时,numpy总是打印正值的符号;使用‘ ’时,它在正值的符号位置总是打印一个空格(空白字符);使用‘-’时,它将省略正值的符号字符。新的默认值为‘-’。

这个新默认值改变了与numpy 1.13相比的浮点输出。在1.13“旧式”打印模式下可以获得旧的行为,请参阅上文的兼容性说明。

hermitian选项已添加到np.linalg.matrix_rank#

新的hermitian选项允许在标准SVD矩阵秩计算和针对对称/hermitian矩阵更高效的特征值方法之间进行选择。

thresholdedgeitems选项已添加到np.array2string#

这些选项以前可以使用np.set_printoptions进行控制,但现在可以作为np.array2string的参数进行每次调用的控制。

concatenatestack增加了out参数#

现在可以使用所需dtype的预分配缓冲区作为这些函数的输出。

支持Windows上的PGI flang编译器#

PGI flang编译器是NVIDIA发布的LLVM的Fortran前端,采用Apache 2许可证。可以通过以下方式调用:

python setup.py config --compiler=clang --fcompiler=flang install

对于这个新编译器,经验很少,所以任何使用它的用户的反馈都将不胜感激。

改进#

random.noncentral_f中的分子自由度只需为正即可。#

在NumPy 1.14.0之前,分子自由度需要大于1,但该分布对大于0的值有效,而现在要求是大于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用于Python的最常见方法是有效的。

在此模式下编译通常会自动启用,并且可以通过setup.py--fcompiler--compiler选项进行选择。此外,还支持将Fortran代码链接到静态OpenBLAS;默认情况下,会查找与gfortran兼容的静态存档openblas.a

np.linalg.pinv现在适用于堆叠矩阵#

以前它仅限于单个二维数组。

numpy.save将数据对齐到64字节而不是16字节#

使用numpy.savenpy格式保存NumPy数组时,会在数组数据之前插入填充以将其对齐到64字节。以前只有16字节(由于版本2代码中的一个错误,有时会更少)。现在对齐是64字节,这与最宽的常用SIMD指令集和最常见的缓存行大小相匹配。这使得npy文件更容易在打开它们的程序中使用mmap,尤其是在Linux上,其中mmap偏移量必须是页面大小的倍数。

NPZ文件现在可以写入,而无需使用临时文件#

在Python 3.6+中,numpy.saveznumpy.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位)的strrepr现在会打印出最短的十进制表示,以便从同类型的值中唯一地标识该值。以前只有float64值才有这种情况。其余的浮点类型现在通常比numpy 1.13中的值要短。以科学记数法打印的数组现在也使用最短的科学表示,而不是像以前那样固定精度。

此外,浮点标量的str在python2中将不再被截断,不像python2的floatnp.double标量的strrepr现在与python3的float相同。

提供了新的函数np.format_float_scientificnp.format_float_positional来生成这些十进制表示。

floatmode新选项已添加到np.set_printoptionsnp.array2string中,该选项控制数组中打印元素的唯一性和四舍五入。新默认值为floatmode='maxprec'precision=8,它将打印最多8位小数,如果元素可以用更少位数唯一表示,则打印更少。一个有用新模式是floatmode="unique",它将输出足够的位数来唯一指定数组元素。

值如inf*jnan*j的NumPy复数浮点标量现在打印为infjnanj,就像纯Python的complex类型一样。

FloatFormatLongFloatFormat类已被弃用,应全部替换为FloatingFormat。同样,ComplexFormatLongComplexFormat应替换为ComplexFloatingFormat

void数据类型元素现在以十六进制表示形式打印#

现在为非结构化np.void元素(例如V4数据类型)打印与Pythonbytes类型兼容的十六进制表示。以前,在python2中,原始void元素数据会打印到stdout,或者在python3中,会显示整数字节值。

用于void数据类型的打印样式现在可以独立自定义#

现在可以使用np.set_printoptionsformatter参数,使用'void'键,而不是像以前那样使用笼统的numpystr键,来独立自定义np.void数组的打印样式。

减少了np.loadtxt的内存使用#

np.loadtxt现在分块读取文件,而不是一次性读取,这显著减少了其对大文件的内存使用。

更改#

结构化数组的多字段索引/赋值#

结构体数组使用多个字段的索引和赋值在多个方面发生了变化,如之前版本中已警告的那样。

首先,使用多个字段索引结构体数组,例如arr[['f1', 'f3']],将返回原始数组的视图而不是副本。返回的视图将包含对应于原始数组中中间字段的额外填充字节,这与1.13中的副本不同,这将影响类似arr[['f1', 'f3']].view(newdtype)的代码。

其次,结构体数组之间的赋值现在将“按位置”发生,而不是“按字段名”发生。目标数组的第N个字段将被设置为源数组的第N个字段,而不管字段名,这与numpy 1.6到1.13版本不同,在那些版本中,目标数组的字段被设置为源数组中同名字段,或者如果源没有该字段则设置为0。

相应地,在计算dtype相等性时,结构体dtype中字段的顺序现在很重要。例如,对于dtype

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,而以前则不是。这使得基于字典的dtype规范(如dtype({'a': ('i4', 0), 'b': ('f4', 4)}))在python < 3.6中是危险的,因为在那些版本中不保留dict键的顺序。

从结构体数组赋值给布尔数组现在会引发ValueError,而1.13中则始终将目标元素设置为True

从具有多个字段的结构体数组赋值给非结构体数组现在会引发ValueError。在1.13中,这只会将源的第一个字段复制到目标。

现在不允许在多字段索引中使用字段“标题”,重复字段名在多字段索引中也是不允许的。

用户指南中关于结构体数组的文档已显著更新,以反映这些更改。

整数和Void标量现在不受np.set_string_function的影响#

以前,与大多数其他numpy标量不同,整数和void标量的strrepr可以通过np.set_string_function控制。现在不再可能。

0d数组打印已更改,array2string的style参数已弃用#

以前,0d数组的strrepr具有特有的实现,对于0d数组a,它们分别返回str(a.item())'array(' + repr(a.item()) + ')',这与numpy标量和更高维的ndarray都不同。

现在,0d数组的str表现得像numpy标量,使用str(a[()]),而repr表现得像更高维的数组,使用formatter(a[()]),其中formatter可以使用np.set_printoptions指定。 np.array2stringstyle参数已被弃用。

此新行为在1.13旧式打印模式下是禁用的,请参阅上文的兼容性说明。

使用数组播种RandomState需要一维数组#

RandomState以前会接受空数组或具有2个或更多维度的数组,这导致了播种失败(空数组)或在设置种子时忽略了部分传入值。

MaskedArray对象显示了更有用的repr#

现在MaskedArrayrepr更接近于能生成它的Python代码,数组现在会显示逗号和dtype。与其他格式更改一样,可以通过1.13旧式打印模式禁用此功能,以帮助迁移doctests。

np.polynomial类的repr更加明确#

它现在显示domain和window参数作为关键字参数,使其更加清晰。

>>> np.polynomial.Polynomial(range(4))
Polynomial([0.,  1.,  2.,  3.], domain=[-1,  1], window=[-1,  1])