前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >重磅!你每天使用的NumPy登上了Nature!

重磅!你每天使用的NumPy登上了Nature!

作者头像
数据科学人工智能
发布2022-03-31 21:49:57
2.9K0
发布2022-03-31 21:49:57
举报

2020年9月16日,Nature刊登了一篇综述性文章介绍Numpy这个Python科学计算核心基础库,请看英文原文Array programming with NumPy[1]

摘要

数组编程为访问、操纵和操作向量、矩阵和高维数组数据提供了功能强大、紧凑且易于表达的语法。NumPy是Python语言的主要数组编程库。它在物理、化学、天文学、地球科学、生物学、心理学、材料科学、工程学,金融和经济学等领域的研究分析流程中起着至关重要的作用。例如,在天文学中,NumPy是用于发现引力波[1]和首次对黑洞成像[2]的软件栈的重要组成部分。本文对如何从一些基本的数组概念出发得到一种简单而强大的编程范式,以组织、探索和分析科学数据。NumPy是构建Python科学计算生态系统的基础。它是如此普遍,甚至在针对具有特殊需求对象的几个项目已经开发了自己的类似NumPy的接口和数组对象。由于其在生态系统中的中心地位,NumPy越来越多地充当此类数组计算库之间的互操作层,并且与其应用程序编程接口(API)一起,提供了灵活的框架来支持未来十年的科学计算和工业分析。

主要工作

在NumPy之前存在两个Python数组程序库。Numeric软件包是在1990年代中期开发的,并使用Python提供了数组对象和数组的函数。Numeric是用C语言实现的,且被链接到线性代数的标准快速实现中[3,4]。其最早的用途之一是在劳伦斯利物摩尔国家实验室[5]中控制C++应用程序进行惯性约束聚变研究。为了处理来自哈勃太空望远镜的大型天文图像,研究人员重新实现了Numeric,称为Numarray,增加了对结构化数组的支持,灵活的索引,内存映射,字节顺序变量,更有效的内存使用,灵活的IEEE 754标准错误处理功能和更好的类型转换规则[6]。尽管Numarray与Numeric高度兼容,但这两个软件包之间的差异足以使社区分裂。但是,在2005年,NumPy成为“两全其美”的统一[7],它将 Numarray的功能与Numeric的小数组性能及其丰富的C API相结合。

如今,15年过去了,NumPy的支撑着几乎每一个做科学计算或数值计算的Python库[8,9,10,11],包括其中SciPy[12],Matplotlib[13],Pandas[14],scikit-learn[15]和scikit-image[16]。NumPy是社区开发的开放源代码库,它提供了多维Python数组对象以及对其进行操作的数组函数。由于其固有的简单性,NumPy数组是Python中数组数据的事实上的交换格式。

NumPy使用中央处理器(CPU)操作内存中的数组。为了利用现代的专用存储和硬件,最近涌现出了大量的Python数组软件库。与Numarray和Numeric的分裂不同,这些新库现在更难打乱用户社区,因为NumPy之上已经建立了多少工作。但是,为了使社区能够使用新的探索性分析技术,NumPy正在过渡到一种中央协调机制,该机制指定了定义良好的数组编程API,并在适当时将其分发给专门的数组实现。

Numpy 数组

NumPy数组是一种可以高效存储和访问多维数组(也称为张量)的数据结构[17],并可以进行多种科学计算。它包含一个指向内存的指针和元数据,其中元数据用于解释存储在内存中的数据,例如“数据类型”,“形状”和“步幅”(图1a)。

图1 NumPy数组合并了几个基本的数组概念。

a)NumPy数组数据结构及其元数据字段。b)用切片和步长索引数组。这些操作返回原始数据的“视图”。c)用掩码、标量坐标或其他数组索引数组,以便它返回原始数据的“副本”。在下面的例子中,使用另一个数组对数组进行索引。这将在执行查找之前广播索引参数。d)向量化有效地将运算应用于元素组。e)二维数组的乘法中的广播。f)规约操作沿一个或多个轴进行。在这个例子中,数组沿选择轴进行求和生成向量,或者沿两个轴连续求和以生成标量。g)对以上一些概念进行示例的NumPy代码。

数组类型(data type)描述存储在数组中的元素的性质。数组具有单一数据类型,并且数组的每个元素在内存中占用相同数量的字节。数据类型包括实数和复数(低精度或高精度),字符串、时间戳和指向Python对象的指针。

数组形状(shape)确定沿每个轴的元素数,而轴数是数组的维数。例如,数字向量可以存储为形状 N 的一维数组,而彩色视频是形状 (T,M,N,3) 的四维数组。

步幅(Stride)用于如何将线性存储的计算机内存解释为多维数组。它们描述了要在内存中在行与行之间或列与列之间跳转需要向前移动的字节数。例如,考虑一个形状为 (4,3) 的二维浮点数组,其中每个元素在内存中占用8个字节。要在连续的列之间移动,我们需要在内存中向前跳转8个字节。然后访问下一行则需要移动 3\times8 = 24 个字节。因此,该数组的步幅为 (24,8) 。NumPy可以按C或Fortran内存顺序存储数组,首先在行或列上进行迭代。这允许使用这些语言编写的外部库直接访问内存中的NumPy数组数据。

用户使用“索引”(访问子数组或单个元素),“运算符”(例如,用于向量化运算的+,-和×和用于矩阵乘法的@),以及数组函数与NumPy数组进行交互;它们共同为数组编程提供了一个易于阅读和表达的高级API,而NumPy则处理了提高操作速度的基本机制。

对数组进行索引将返回满足特定条件的单个元素,子数组或元素(图1b)。甚至可以使用其他数组对数组进行索引(图1c)。在可能的情况下,检索子数组的索引将在原始数组上返回一个“视图”,以便在两个数组之间共享数据。这提供了一种强大的方法来处理数组数据的子集,同时限制了内存的使用。

为了补充数组语法,NumPy包括对数组执行向量化计算的函数,包括算术,统计和三角函数(图1d)。向量化(对整个数组而非单个元素进行操作)对于数组编程至关重要。这意味着使用其他语言(例如C语言)需要数十行表达的操作通常可以实现为单个清晰的Python表达式。这样可以生成简洁的代码,使用户可以将精力集中在分析上,而NumPy则以近乎最佳的方式处理数组元素的循环。例如,考虑到最大程度地利用计算机的快速缓存。

在具有相同形状的两个数组上执行向量化操作(例如加法)时,很清楚会发生什么。通过广播,NumPy允许形状不同的数组进行运算,并产生合乎直觉的结果。一个简单的例子是将标量值添加到数组。广播也可以推广到更复杂的例子,例如缩放数组的每一列或生成坐标网格。在广播中,一个或两个数组实际上是虚拟复制的(即不在内存中复制任何数据),以使操作运算的数组形状匹配(图1d)。当使用数组对数组进行索引时,也会应用广播(图1c)。

其他的数组函数,例如求和,均值和最大值,将执行逐个元素的“归约”,在单个数组的一个、多个或所有轴上汇总结果。例如,在 n 维数组的 d 个轴进行求和将产生 n-d 维结果(图1F)。

NumPy还包含其他数组函数,用于创建、重塑、连接和填充数组;搜索、排序和计数数据;读写文件。它提供了用于产生伪随机数的广泛支持,包括各种各样的概率分布,使用不同的后端,例如OpenBLAS[18,19]和为CPU的优化的Intel MKL加速线性代数运算(更多细节请参见补充方法) 。

总而言之,简单的内存数组表示形式,紧密模拟数学的语法以及实用的数组函数组合形成了一种高效且功能强大的数组编程语言。

Python 科学计算生态系统

Python是一种开放源代码的通用解释型编程语言,非常适合诸如清洗数据、与Web进行资源交互和解析文本之类的标准编程任务。增加快速的数组运算和线性代数,使科学家能够在一种编程语言中完成所有工作,这种众所周知的易学易教的优势,已通过许多大学用作主要学习语言而证明。

虽然NumPy不是Python标准库的一部分,它也可以从与Python开发人员的良好关系中受益。多年来,Python语言增加了新功能和特殊语法,因此NumPy将具有更简洁和易于阅读的数组概念。由于它不是标准库的一部分,因此NumPy能够规定其自己的发布策略和开发模式。

在历史、开发和使用方面,SciPy和Matplotlib与NumPy紧密结合。SciPy提供了用于科学计算的基本算法,包括数学、科学和工程库。Matplotlib生成可发布的图形和可视化文件。NumPy、SciPy和Matplotlib的结合,以及高级交互环境,例如IPython[20]或Jupyter[21],为Python的数组编程奠定了坚实的基础。Python科学计算生态系统(图2)建立在此基础之上,提供了广泛用于特定技术的库[15,16,22],这些特定技术库又是众多特定领域的项目[23,24,25,26,27,28]的基础。NumPy是数组函数库生态系统的基础,它提供了文档标准,提供了数组测试基础结构,并为Fortran和其他编译器增加了编译支持。

图2 NumPy是科学的Python生态系统的基础。

许多研究小组设计了大型复杂的科学库,这些库为生态系统添加了特定于应用的功能。例如,eht-imaging [29]是由Event Horizon Telescope合作小组开发的,用于无线电干涉测量成像,分析和仿真,它依赖于Python科学计算生态系统的许多底层组件。特别是,EHT合作小组使用该库对黑洞进行了首次成像。eht-imaging在每个处理步骤中都使用NumPy数组存储和处理数字数据:从原始数据到校准和图像重建。SciPy提供用于一般图像处理任务(例如过滤和图像对齐)的工具,而scikit-image是扩展SciPy的图像处理库,提供了更高级别的功能,例如边缘滤镜和霍夫变换。scipy.optimize模块执行数学优化。NetworkX[22]用于复杂网络分析的软件库,用于验证图像比较的一致性。Astropy处理标准的天文文件格式并计算时间-坐标转换 [23,24]。Matplotlib用于可视化数据并生成黑洞的最终图像。

基于数组编程基础和周围的工具生态系统创建的交互式环境,例如IPython或Jupyter,非常适合进行探索性数据分析。用户可以流畅地检查、操纵和可视化他们的数据,并快速迭代以完善编程语句。然后将这些语句组合成命令式或函数式程序,或包含计算和叙述的笔记本。超出探索性工作的科学计算通常在文本编辑器或诸如Spyder等集成开发环境(IDE)中完成。这种丰富而高效的环境使Python在科学研究中颇受欢迎。

为了完善该工具以进行探索性工作和快速制作原型,NumPy建立了一种使用经过时间考验的软件工程实践来改善协作并减少错误的文化[30]。这种文化不仅被项目领导者采用,而且还热情地向新来者传授。NumPy团队很早就采用分布式修订控制和代码审查来改善代码协作,并为NumPy的每个拟议变更进行连续测试,从而运行大量自动测试。该项目还具有全面的,高质量的文档和源代码[31,32,33]。

采用这种使用最佳实践来生产可靠的科学软件的文化已经被NumPy之上构建的生态库所广泛采用。例如,在皇家天文学会最近颁发给Astropy的奖项中,他们指出[34]:

“Astropy项目已经为数百名初级科学家提供了专业标准软件开发实践的经验,包括版本控制的使用,单元测试,代码审查和问题跟踪程序。对于现代研究人员而言,这是一项至关重要的技能,而物理学或天文学的正规大学教育通常却不具备这种技能。”

社区成员明确合作,通过课程来解决研讨会来解决正式教育的缺乏[35,36,37]。

数据科学、机器学习和人工智能最近的快速发展进一步并极大地促进了Python的科学使用。它的重要应用例子,例如eht-imaging,现在几乎在自然科学和社会科学的每个学科中都有。这些工具已成为许多领域的主要软件环境。NumPy及其生态系统通常在大学课程,新兵训练营和暑期学校中教授,并且是全球社区会议和研讨会的重点。NumPy及其API已真正普及。

数组扩展和互操作性

NumPy在CPU上提供内存中的多维、同构类型(即单指针和步幅)数组。它运行在从嵌入式设备到世界上最大的超级计算机的机器上,性能接近编译语言。在大多数情况下,NumPy都解决了绝大多数数组计算用例。

但是,科学数据集现在通常超过了单台计算机的存储容量,并且可以存储在多台计算机上或存储在云中。此外,最近对加速深度学习和人工智能应用程序的需求导致了专用加速器硬件的出现,包括图形处理单元(GPU)、张量处理单元(TPU)和现场可编程门阵列(FPGA)。由于其内存中数据模型,NumPy当前无法直接利用此类存储和专用硬件。但是,分布式数据以及GPU、TPU和FPGA的并行执行都可以很好地映射到数组编程的范式:因此,在可用的现代硬件架构和利用其计算能力所必需的工具之间造成了鸿沟(gap)。

社区为填补这一空白所做的努力导致了新的数组实现方式的激增。例如,每个深度学习框架都创建了自己的数组。PyTorch [38],Tensorflow [39],Apache MXNet [40],JAX 数组都具有以分布式方式在CPU和GPU上运行的能力,并使用惰性评估来进行其他性能优化。SciPy和PyData/Sparse都提供稀疏数组,它们通常包含很少的非零值,并且仅将那些值存储在内存中以提高效率。此外,有些项目以NumPy数组作为数据容器构建,并扩展了其功能。Dask通过这种方式使分布式数组成为可能,而带标签的数组(为清晰起见,是指数组的名称而不是索引),通过xarray比较x [:, 1]x.loc [:,'time'][41]。

这些库通常模仿NumPy API,因为这降低了新手进入的门槛,并为更广泛的社区提供了稳定的数组编程接口。反过来,这可以防止破坏性分裂,例如Numeric和Numarray之间的分歧。但是,探索使用数组的新方法本质上是实验性的,实际上,一些有前途的库(例如Theano和Caffe)已经停止开发。而且,每当用户决定尝试一种新技术时,他们都必须更改导入语句,并确保新库实现他们当前使用的NumPy API的所有部分。

理论上,使用NumPy函数或语义在专门的数组上进行操作将很简单,以便用户可以编写一次代码,便可以在NumPy数组、GPU数组、分布式数组等之间切换。为了支持外部数组操作,NumPy添加了使用指定明确的API充当中央协调机制的功能(图2)。

为了促进这种互操作性,NumPy提供了“协议”(或操作合同)。允许将专门的数组传递给NumPy函数(图3)。NumPy会根据需要将操作分派到原始库。支持超过四百种最流行的NumPy函数。该协议由广泛使用的库(例如Dask,CuPy,xarray和PyData/Sparse)实现。由于有了这些发展,用户现在可以使用Dask将计算从一台机器扩展到分布式系统。协议的组合也很好,允许用户通过嵌入在Dask数组中的CuPy数组在分布式多GPU系统上大规模重新部署NumPy代码。使用NumPy的高级API,用户可以在具有数百万个内核的多个系统上利用高度并行的代码执行,所有这些都只需最少的代码更改[42]。

图3 NumPy的API和数组协议向生态系统公开了新的数组。

在此示例中,在Dask数组上调用了NumPy的mean函数。调用通过分派到适当的库实现(在本例中为Dask),并产生一个新的Dask数组。将此代码与图1g中的示例代码进行比较。

现在这些数组协议是NumPy的关键功能,并且预计会变得更加重要。NumPy开发人员(其中许多人是本综述的作者)反复完善和添加协议设计以提高实用性并简化采用。

讨论

NumPy将数组编程的表达能力、C语言的性能以及Python的可读性、可用性和多功能性结合在一起,形成了一个成熟、经过良好测试、记录良好并由社区开发的库。Python科学计算生态系统中的库提供了最重要算法的快速实现。在需要进行极端优化的地方,可以使用编译语言,例如Cython [43],Numba [44]和Pythran [45]; 这些语言扩展了Python加速了某些瓶颈。由于NumPy具有简单的内存模型,因此很容易编写低级的,手动优化的代码(通常使用C或Fortran)来操纵NumPy数组并将其传递回Python。此外,使用数组协议,可以对现有代码进行最小更改的情况下利用专用硬件加速。

NumPy最初是由学生、教职员工和研究人员开发的,目的是为Python提供高级的开源数组编程库,该库可免费使用,并且不受许可证服务器和软件保护加密狗的约束。有一种共同的意义,那就是为了其他许多人的利益而共同建设一些东西。在一个志趣相投的人的欢迎社区中参加这种努力,对许多早期贡献者都具有强大的吸引力。

这些用户开发人员经常不得不从头开始编写代码来解决他们自己或同事的问题-通常使用Python之前的底层语言(例如Fortran [46]和C)。对于他们来说,交互式、高层的数组库优势很明显。这个新工具的设计是由其他强大的交互的编程语言用于科学计算的基础,例如Basis[47,48,49,50],Yorick[51],R [52] 和APL [53],以及商业的语言和环境中,例如IDL(交互式数据语言)和MATLAB。

最初试图向Python添加数组对象的尝试成为了充满活力的工具生态系统的基础。现在,大量的科学工作取决于NumPy的正确、快速和稳定。它不再是一个小型社区项目,而是核心科学基础设施。

开发人员的文化已经成熟:尽管最初的开发是高度非正式的,但NumPy现在有了路线图以及提议和讨论大型变更的过程。该项目具有正式的治理结构,由NumFOCUS资助,NumFOCUS是一家非营利性组织,旨在促进研究,数据和科学计算领域的开放实践。在过去的几年中,该项目吸引了由Moore和Sloan基金会赞助的首个资助开发项目,并获得了Chan Zuckerberg Initiative的“开源软件基础”计划的一部分奖项。有了这笔资金,该项目能够(而且能够)持续几个月的关注,以实施实质性的新功能和改进。那就是

NumPy不再只是科学的Python生态系统的基础数组库,它已成为张量计算的标准API,以及Python中数组类型和技术之间的中央协调机制。继续努力扩展和改进这些互操作性功能。

在接下来的十年中,NumPy开发人员将面临若干挑战。将开发新的设备,并将发展现有的专用硬件,以满足摩尔定律日益减少的收益。将会有越来越多的数据科学从业人员,其中很大一部分将使用NumPy。随着诸如光片显微镜和大型天气观测望远镜(LSST)54之类的设备和仪器的采用,科学数据的收集规模将继续增加。诸如Rust 55,Julia 56和LLVM 57之类的新一代语言,解释器和编译器将创建新的概念和数据结构,并确定其可行性。

通过本文描述的机制,NumPy准备迎接这种不断变化的形势,并继续在交互式科学计算中发挥领导作用,尽管要做到这一点需要政府,学术界和行业的持续资助。但是,重要的是,为了使NumPy满足下一个十年数据科学的需求,它还需要新一代的研究生和社区贡献者来推动它的发展。

参考资料

[1]Array programming with NumPy: https://www.nature.com/articles/s41586-020-2649-2

本文参与?腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-09-18,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 数据科学人工智能 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 摘要
  • 主要工作
  • Numpy 数组
  • Python 科学计算生态系统
  • 数组扩展和互操作性
  • 讨论
    • 参考资料
    相关产品与服务
    对象存储
    对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
    http://www.vxiaotou.com