美文网首页
SciPy 1.0:Python科学计算的基本算法

SciPy 1.0:Python科学计算的基本算法

作者: 哈哈哈8888 | 来源:发表于2020-02-18 23:10 被阅读0次

序言

本文内容编译自:Pauli Virtanen and et. al., SciPy 1.0: fundamental algorithms for scientific computing in Python. Nature Method,published 03 Feb, 2020,DOI:https://doi.org/10.1038/s41592-019-0686-2

本文使用 Google translate 翻译后,人工逐句进行了核对校理。部分数学专业名词可能存在翻译不准确的问题,请注意。中文版本排版基于 Markdown ,使用 macOS typora 构建,PDF 为 typora 自动导出。

本文为编译,不保证与原文的一一对应。译者对心有戚戚的段落加粗以表感叹,原文无。

如果你觉得还不错,欢迎打赏几毛钱让我去买六味地黄丸。

更新历史:

版本 日期 说明
v0.99 Feb 18, 2020 翻译整理完成的第一个完整版本,不含参考文献,也没有加入的计划

摘要

SciPy是用于Python编程语言的开源科学计算库。自2001年发布以来,SciPy已成为Python科学算法的事实标准。它有600多个独立代码贡献者,数千个依赖程序包,超过100,000个依赖于它的代码库,每年下载量数百万次。本文中,我们概述了SciPy 1.0的功能和开发实践,重点介绍了一些最新的技术进展。

正文

SciPy是Python编程语言的数值程序库,为科学问题建模和求解提供基本模块。SciPy包括了用于优化、积分、插值、特征值问题、代数方程、微分方程和许多其他类型问题的算法;它还提供了专门的数据结构,例如稀疏矩阵和k维树。SciPy的构建基于 NumPy ,主要使用了NumPy 提供的数组数据结构和相关的快速数值程序。SciPy本身又是更高层级的科学库(包括scikit-learn和scikit-image)构建的基础。世界各地的科学家、工程师和其他相关人士都在使用SciPy。例如,引力波的分析中使用的的脚本引用了SciPy的若干子包,M87黑洞成像项目也引用SciPy。

最近,SciPy发布了1.0版。一般而言,1.0 具有里程碑意义,表示库的API(应用程序编程接口)达到了在生产中可信任的成熟度。但是,SciPy的版本号并不能反映它的历史,它在1.0 之前就已成为标准,并在科研和工业中得到广泛采用。

SciPy能做到这一点着实令人惊讶,甚至有些反常。2001年启动时,资金支持很少,主要代码是由研究生编写的——其中许多人没有接受计算机科学教育,而且大多并没有得到他们导师的支持。甚至可以想象,一小群“散兵游勇”编写的程序颠覆了已经建立起来的科研软件生态系统——有数以百万计的资金和数百高素质工程师——是多么荒谬。

然而,完全开放的工具栈背后的哲学动机,加上一个充满激情、友好的社区和一个单一的焦点,从长远来看被证明是成功的。他们不仅建立了本文所述的库,还带来了相关软件包组成的的整个生态系统(https://wiki.python.org/moin/NumericAndScientific)和以之为中心的各种社交活动(https:// wiki.python.org/moin/PythonConferences)。SciPy生态系统中的软件包都有高标准的实现、文档和测试。这个社区管理和开发的文化是:渴望学习并采用更好的实践

背景

这里我们有选择性的列出SciPy发展中的一些里程碑和重要事件。我们在此处仅突出了部分内容,更重要的是要知道:像SciPy这样的项目,只有在众多贡献者的贡献下才会产生——太多的贡献者无法一一提及,但每个人都为解决难题贡献了自己的力量。

Python是由Guido van Rossum在1980年代后期设计的一种解释型高级通用计算机编程语言。Python具有动态类型系统,强调可读性和快速原型设计。与当时许多其他成熟的计算平台不同的是,作为一种通用编程语言,它并未对科学数据结构或算法提供特别的支持。然而,科学家很快发现了该语言的优点,例如调用C和Fortran库并以交互方式使用这些库的能力。科学家因此可以访问已有的各计算库,而无需关心诸如存储管理之类的低级编程概念。

1995年,MIT的研究生Jim Hugunin在新建立的Python Matrix Special Interest Group(Matrix-SIG)邮件列表中写下了第一条消息:

Python社区中似乎很多人对将数值运算添加到Python中感兴趣。我自己的愿望是能有一个尽可能全的基于矩阵的函数库(线性代数,本征函数,信号处理,统计信息等)。为了确保所有这些库都可以互操作,需要在可用于表示数字数组的基本矩阵对象上有一个共识。

在接下来的几个月中,Jim Fulton、Jim Hugunin、Paul Dubois、Konrad Hinsen和Guido van Rossum等人在该邮件列表上的交流最终导致名为Numeric的包的创建,该包支持高维数值数组。Jim Hugunin解释了Python用于数值计算的实用性:

在过去的8年中,我把几乎所有可用的数值语言用了一遍。我注意到,随时间推移,这些语言的设计人员正在稳步增加人们希望在通用编程语言中发现的更多功能。

这是Python在科学领域的一个突出特性,也是它在数据科学领域如此成功的原因之一:它不是为数值和科学计算设计语言中添加通用功能,而是在通用语言中添加了科学功能。这种模式扩大了可以轻松解决的问题的范围,扩展了易于访问的数据来源,并增加了为平台开发代码的社区的规模。

SciPy的创始

1990年代后期,Matrix-SIG上出现的讨论表达了对完整科学数据分析环境的期望。Mayo Clinic的Travis Oliphant博士发布了多个建立在 Numeric 包上的包,提供了用于信号处理、特殊函数、稀疏矩阵、正交化、优化、快速傅立叶变换等领域的算法。其中有一个软件包是Multipack,包装了Fortran和C库的扩展模块,用于解决非线性方程和最小二乘问题、积分微分方程和样条曲线拟合。当时还是本科生(现为SciPy核心开发人员)的Robert Kern提供了Windows下的编译说明。大约在同一时间,来自爱沙尼亚的Pearu Peterson博士发布了用于绑定Python和Fortran代码的命令行工具F2PY,并编写了用于线性代数和插值的模块。Duke University的研究生Eric Jones为撰写论文编写了一些软件包,包括并行工作调度器和基因算法优化程序。Harvard Medical School的博士后Gary Strangman发表了几种描述性和推论性的统计程序。

专栏1 | SciPy是基于强大的Python和Numeric的开源软件包,提供广泛的快速的科学和数值计算功能

SciPy的当前模块集包括以下内容:

  • 特殊函数(Bessel,Hankel,Airy等)
  • 信号/图像处理
  • 2D绘图功能
  • 积分
  • ODE求解器
  • 优化(单纯型,BFGS,Newton-CG等)
  • 遗传算法
  • 数值到C ++表达式的编译器
  • 并行编程工具
  • 样条和插值
  • 其他

有了丰富的编程环境和立等可用的数值数组对象,开发完整的科学软件包的时机成熟了。2001年,Eric Jones和Travis Vaught在美国Texas 的 Austin创立Enthought Scientific Computing Solutions(现Enthought,Inc.)。为了简化工具栈,他们创建了以SciPy库为中心的SciPy项目,该项目将涵盖上述所有软件包。该项目迅速发展:2 月,网站和代码存储库搭建了起来;6月,公布了邮件列表;8月,发布了第一个版本;9 月,发布了第一份文档。2002年9月,在加州理工学院举行了第一次SciPy研讨会。研讨会单一主题,为期两天,有50位参与者,其中许多人是SciPy和周边库的开发者。

此后,科学Python开始引起更多严肃的关注;作为研究生附带项目编写的代码已发展为国家实验室和研究机构的基本基础架构。例如,Lawrence Livermore National Laboratory(LLNL)的Paul Dubois接管了Numeric的维护工作,并出资编写了手册;负责哈勃太空望远镜科学研究的Space Telescope Science Institute(STScI)决定用Python取代他们自己开发的脚本语言。随着STScI在哈勃太空望远镜数据分析中使用 Python 的范围越来越大,他们遇到了Python数值数组容器的问题。原Numeric包适用于小型数组,在STScI处理大型图像时不再适用。Numeric维护者们决定编写可用于处理更大规模数据的NumArray包。不幸的是,NumArray对于规模数组效率不高。2005年,Travis Oliphant各取Numeric与NumArray之精华,从而解决了这个二难问题。2006 年 10 月 29 日,NumPy 1.0发布,为统一的科学Python社区走向成熟铺平了道路。

SciPy的成熟

SciPy在经历了长期显著成长和广泛采用后,到2000年代中后期开始成熟。SciPy库本身的范围缩小了,但生态系统范围则通过一个新的辅助包得以扩大:scikit。它是在SciPy外开发的一个补充库,允许在保持类似风格和开发方法论下更快速地探索实验想法。就SciPy本身而言,其工具、开发、文档和发布过程变得更加专业。该库在开源项目中可承受的条件下,通过吸收业界最佳实践,小心扩展。

早期版本的SciPy的文档很少,但随着2006年《<u>NumPy指南</u>》的发布,这种情况开始改变。2007年,Sphinx让Python代码中的注释文本(文档字符串)自动呈现为超文本和PDF文档成为可能。2008年,pydocweb以类似Wiki的方式实现了协作文档的开发。SciPy的文档项目使用这些工具来完成SciPy用户功能的文档:作为对高质量文档的回报,他们给来自世界各地的贡献者发纪念T恤衫。他们共收到超过75人的贡献,最终产生了884页的手册。从那时起,SciPy就一直致力于在正常开发周期中维护高质量的文档。

在早期的SciPy研讨会中,经常性的主题反映了开发的状态。一度重点放在了底层数组、绘图、并行处理、加速/包装和用户接口上。2004年,开始出现SciPy在科学问题中的应用的演讲。这次活动开始吸引来自社区以外的更多主题演讲者,例如Guido van Rossum(Python之父,2006年),IvanKrstić(One Laptop per Child,2007年),Alex Martelli(Google,2008年)和Peter Norvig( Google Research,2009年)。核心开发人员小团体的非正式研讨会发展成为国际性大会。会议有数百名与会者,有了持续增加的赞助,发布了论文集,并为参加会议的学生提供奖学金。2010年,美国SciPy会议有了多个主题,其他地方的志愿者开始组织卫星会议,例如EuroSciPy(2008年起)和SciPy India(2009年起)。专门研讨科学Python的特别环节和小型专题讨论会开始出现在许多其他会议中。例如,2009年国际计算科学与工程大会(CSE)上的三部分小型专题讨论会成为<u>SIAM新闻</u>的亮点。

到2007年,Python在科学和工程领域的影响力已足够强大,IEEE Computing in Science and Engineering的Paul Dubois编辑了Python的科学应用特刊。但对普通读者而言,他仍需要获得更多其他信息来确定Python是否对自己的工作有用。2011年3月/ 4月号的《<u>面向科学家和工程师的Python</u>》特刊更侧重于科学Python生态系统的核心部分,包括NumPy ,Cython和Mayavi。Python开始无处不在,杂志开始出版具体领域的特刊。例如,2015年,《<u>神经信息学前沿</u>》出版了总题为Python in Neuroscience的25篇文章合集——覆盖建模和仿真、数据收集、电生理学、可视化以及刺激生成和表示等主题。

专栏2 |包的组织

SciPy库被组织为子包的集合。这16个子包包括数学构造块(如线性代数、傅立叶变换、特殊函数)、数据结构(如稀疏矩阵、k-D树)、算法(如数值优化和积分、聚类、插值、图算法、计算几何)和更高级别的数据分析功能(如信号和图像处理、统计方法)。在这里,我们总结了每个子包的范围和功能。 更多信息参见SciPy教程(https://docs.scipy.org/doc/scipy/reference/tutorial/)和API参考(https://docs.scipy.org/doc/scipy/reference/index.html#api-reference)。

  • clustercluster子包含cluster.vqcluster.hierarchy,前者提供矢量量化和k均值算法,后者提供分层和聚类函数。
  • constants。物理和数学常数,包括CODATA推荐的基本物理常数值。
  • fftpack。快速傅立叶变换例程。除FFT外,该包还包括离散正弦和余弦变换以及伪微分运算符。
  • integrate。本包提供单变量和多变量定积分的数值计算以及用于求解常微分方程(包括初值问题和两点边值问题)的工具。
  • interpolate。包含样条函数和类,一维和多维(单变量和多变量)插值类,Lagrange和Taylor多项式插值器以及FITPACK和DFITPACK函数的包装器。
  • io。用于读写Matlab、IDL、Matrix Market,Fortran,NetCDF,Harwell-Boeing,WAV和ARFF数据的函数和类。
  • linalg。线性代数函数,包括矩阵基本函数,例如迹、行列式、范数和条件数; Ax = b的基本求解器;用于Toeplitz矩阵、循环矩阵、三角矩阵和其他结构化矩阵的专业求解器;最小二乘和广义逆计算函数;特征值和特征向量计算(基本和广义)函数;矩阵分解,包括Cholesky、Schur、Hessenberg、LU、LDLT、QR、QZ、奇异值和极分解;创建特殊的矩阵,例如对角线、Toeplitz、Hankel、伴随、Hilbert等的函数。
  • ndimage。包含用于多维图像处理的各种函数,包括卷积以及各种线性和非线性滤波器(高斯滤波器、中值滤波器、Sobel滤波器等);数学形态函数。
  • misc。不适合其他子程序包的功能集合。尽管此子包在SciPy 1.0中仍然存在,但我们始终在努力将其淘汰或重定位到其他子包中从而删除本包。
  • odr。正交距离回归,包括Fortran库ODRPACK 的Python包装器。
  • optimize。包括单纯形和内点线性规划求解器,许多非线性最小化算法的实现,最小二乘曲线拟合的例程以及用于寻根的常规非线性求解器的集合。
  • signal。专注于信号处理和基本线性系统理论,包括卷积和相关、样条曲线、滤波和滤波器设计、连续和离散时间线性系统、波形生成、窗口函数、小波计算、峰发现和频谱分析等相关的函数。
  • sparse。包括稀疏矩阵的几种表示形式的实现。 scipy.sparse.linalg提供了适用于稀疏矩阵的线性代数例程的集合,包括线性方程求解器、特征值分解、奇异值分解和LU分解。 scipy.sparse.csgraph提供了图算法的集合,使用稀疏矩阵表示图。算法包括连接组件、最短路径、最小生成树等等。
  • spatial。提供空间数据结构和算法,包括k-d树、Delaunay三角剖分、凸包和Voronoi图。 scipy.spatial.distance提供了大量的距离函数,以及用于计算给定点集合中所有向量对之间或两个点集合中所有对之间距离的函数。
  • special。得名于传统上的特殊函数,但在不断演进中,本包已包括了经典特殊函数之外的函数。对此包更合适的定位简单来说,就是有用的函数。包含的大量的经典特殊函数,例如Airy、Bessel等;正交多项式族;伽玛函数及其相关函数;用于为几种概率分布计算PDF,、CDF和分位数的函数;信息论函数;组合函数combfactorial等等。
  • stats。本包提供了大量连续和离散概率分布函数,每种分布都有计算PDF或PMF、CDF、矩量和其他统计信息的函数,以及生成随机变量的函数等。统计检验,包括均值/中位数/方差均等检验(例如t检验)和检验是否从某个分布中抽取样本(例如Kolmogorov-Smirnov检验);相关度量,包括Pearson的r,Kendall的τ和Spearman的ρ系数;描述性统计数据,包括核密度估计;数据转换,例如Box-Cox功率转换等。

SciPy的今天

截至2019年2月,SciPy库包含将近600,000行开源代码,组织在 16 个子包中(专栏2)。开发团队和社区当前主要在GitHub(一个在线版本控制和任务管理平台)上进行交互和操作。超过110,000个GitHub repo和6,500个包依赖于SciPy 。下面的“关键技术改进”部分讨论了SciPy 1.0之前三年中的一些主要功能亮点,图1突出显示了里程碑。

S**图1:从2001年SciPy的初始版本到2017年SciPy 1.0的里程碑**

架构和实现选择

项目范围

SciPy提供科学计算的基本算法。其范围的广度来自于可用数学软件指南(GAMS)的分类系统。在像线性代数这种进展相对较慢的领域,SciPy旨在提供完整的覆盖。在其他领域,它的目的是提供基本的构建块,同时与该领域的专用软件包进行良好的交互。例如,SciPy提供了人们希望在统计教科书中找到的内容(概率分布、假设检验、频率统计、相关函数等);Statsmodels提供了更高级的统计估计和推断方法,scikit-learn 涵盖了机器学习,PyMC3 ,emcee和PyStan涵盖了贝叶斯统计和概率模型,scikit-image提供了比SciPy ndimage更强大的图像处理功能,SymPy提供了用于符号计算的Python接口,sparse.csgraphspatial提供了用于操作图和网络的——所谓基本,是与诸如NetworkX这样的专用库相比而言的。

我们使用以下条件来确定是否在SciPy中加入新功能:

  • 该算法与科学的多个领域相关。
  • 该算法非常重要。比如,它足够经典可以进教科书;或者基于高被引的同行评审文章。

在软件系统和架构方面,SciPy的范围与NumPy的范围相匹配:用于单机内存计算,支持多种数据类型和流程体系脚骨。在1.0版发布时,分布式计算和对图形处理单元(GPU)的支持已明显超出范围,但我们的路线图已对此进行了修订(请参见讨论)。

语言选择

根据使用linguist库进行分析可知,SciPy的代码组成为:Python大约50%,Fortran为25%,20%为 C,3%为Cython,2%为C ++,以及少量的TeX, Matlab,shell脚本和Make。在SciPy中辅助编程语言的布局是对与Python(即Cython)可良好交互的功能强大的性能增强语言的折中。数十年来,以上语言及其库的使用被证明是可靠且性能卓越的。

尽管Fortran是一种老语言,但它仍然是一种高性能的科学编程语言并在当代持续使用。因此,我们包装了以下久经考验的Fortran库,在得益于Python便利性的同时不减性能:QUADPACK 和ODEPACK 用于数值积分和初值问题;FITPACK ,ODRPACK 和MINPACK 用于曲线拟合和最小二乘最小化;FFTPACK 用于傅立叶变换; ARPACK 用于解决特征值问题;ALGORITHM 644用于计算贝塞尔函数;CDFLIB 用于计算累积密度函数。

C语言在SciPy中排名第三。在数十年里,C 是科学计算中非常完善的语言。我们在SciPy中包括的 C 库包括:trlib ,用于优化,SuperLU 用于求解稀疏线性系统,Qhull 用于计算几何,Cephes用于特殊函数。

Cython是结合Python的最佳部分和底层C / C ++的一个范例。我们经常将Cython用作胶水,粘合成熟的、用C / C ++编写的底层科学计算库与SciPy提供的Python接口。我们还使用Cython来增强Python代码的性能,特别是在那些频繁使用的内部循环的情况,此时静态类型的编译代码优势明显。

在实现新功能时,Python仍然是首选语言。如果Python性能是一个问题,退而求Cython,接下来才是C,C ++或Fortran(按此顺序)。这样做的主要动机是可维护性:Cython具有最高的抽象级别,大多数Python开发人员都会理解它。C也广为人知,对于当前的核心开发团队而言,C比C ++和Fortran更易于管理。

考虑到SciPy在科学Python生态系统的基础性地位,通常不太可能采用新语言或改变关键依赖。我们的选择在很大程度上是由长期稳定性驱动的。尽管GPU加速、新的转码库和最新的JIT编译方法(例如Numba)非常强大,但他们超出了主SciPy库的领地。我们最近加大了对与上述一些选项的兼容性支持,并且我们的完整测试套件在1.0发布时已通过了PyPy JIT编译器。

API和ABI的发展

SciPy的API包含大约1,500个函数和类。我们对API演进的策略是:可以添加新功能;但只在给用户带来的好处超过(通常是很大的)代价的情况下且在向这些用户发出明确的弃用警告至少一年后,才会删除或更改现有功能。总的来说,鉴于我们靠近科学Python计算栈的根基,我们鼓励库 API进行更改以提高清晰性,但强烈建议不要破坏向后兼容。

除了Python API,SciPy还具有C和Cython接口。因此,我们还必须考虑应用程序二进制接口(ABI)。该ABI长期以来一直稳定,我们的目标是仅以向后兼容的方式对其进行改进。

关键技术进步

在这里,我们描述了过去三年中取得的关键技术进步。

数据结构

sparse matrix稀疏矩阵scipy.sparse提供了七个稀疏矩阵数据结构,或稀疏格式。最重要的是行和列压缩格式(分别为CSR和CSC)。它们提供快速的主轴索引和快速的矩阵-向量乘法,并且在整个SciPy和相关程序包中大量使用。

在过去三年中,我们对稀疏矩阵处理核心进行了重写并提高了其性能。现在,CSC和CSR矩阵的迭代和切片索引速度提高了35%,坐标(COO)/对角线(DIA)到CSR / CSC矩阵格式转换的速度有所提高。SuperLU已更新至版本5.2.1,通过利用本sparse 的部分功能,其底层实现得到增强。

从新功能的角度来看,scipy.sparse矩阵和线性运算符现在支持Python矩阵乘法(@)运算符。我们添加了scipy.sparse.norm计算稀疏矩阵范数,scipy.sparse.random来从任意分布中提取随机变量。此外,我们还全力使scipy.sparse API与等效的NumPy API保持一致。

cDKTreescipy.spatial.ckdtree模块实现了空间分割数据结构,可在ķ维空间进行点的组织。本模块是用C ++的模板类改写的,增加了对周期性边界条件的支持——该条件通常用于物理过程的仿真。

2013年,来自cKDTree.queryk最近邻搜索的时间复杂度约为对数线性,与其形式描述一致。随后,我们通过C ++重新实现cKDTree.query来增强其功能,消除了内存泄漏并允许释放全局解释器锁(GIL),以便可以使用多个线程。该方法在保留渐近复杂性的同时普遍提高了任何给定问题的性能。

2015年,SciPy添加了sparse_distance_matrix例程生成KDTree对象之间的近似稀疏距离矩阵,该例程忽略了哪些超过用户提供值的距离。该例程不限于常规的L2(欧几里得)范数,支持1到无穷大之间的任何Minkowski p范数。默认返回的数据结构是基于字典(DOK)的稀疏矩阵,这对于矩阵构造非常有效。这种组装稀疏矩阵的哈希方法比使用CSR格式构建的哈希方法快7倍。C ++级别的稀疏矩阵构造释放Python GIL以提高性能。一旦构造了矩阵,距离值检索就具有摊销的恒定时间复杂度,DOK结构可以有效地转换为CSR、CSC或COO矩阵以实现快速的算术运算。

2015年,我们对cKDTree对偶树计数算法进行了增强以支持权重,这在许多科学应用中都很重要,例如计算星系相关函数。

已编译的代码的统一绑定

LowLevelCallable

SciPy 0.19版开始允许用户将低级函数包装在scipy.LowLevelCallable对象中,从而减少直接由 Python调用已编译的C函数(例如使用Numba或Cython生成的函数)的开销。支持的低级函数包括PyCapsule对象,ctypes函数指针和cffi函数指针。此外,可以使用scipy.LowLevelCallable.from_cython从Cython模块自动生成低级回调函数。

Cython对BLAS,LAPACK和特殊函数的绑定

SciPy提供特殊函数、使用基本线性代数子程序(BLAS)和线性代数程序包(LAPACK)例程已有很多年了。SciPy现在还包括适用于许多BLAS和LAPACK例程的Cython包装器(2015年添加),在scipy.special包中提供更多特殊函数(2016年添加),分别见于scipy.linalg.cython_blas,scipy.linalg.cython_lapackscipy.special.cython_special。用Cython写算法时,直接使用SciPy包装器要比间接使用SciPy的Python API调用更为有效。这些用于Cython的低级接口也可以在SciPy代码库之外使用,以访问包装的库中的函数同时避免Python函数调用的开销。许多情况下,本方法可使性能提高一到两个数量级。

开发人员也可以在不链接包装库时使用低级Cython接口,这令其他扩展可以避免查找和使用正确库的复杂性。避免这种复杂性在包装以Fortran编写的库时尤为重要。这些低级包装器不仅可以在没有Fortran编译器的情况下使用,而且无需处理所有不同的Fortran编译器ABI和名称修改方案即可使用。

为了正确性和易于维护,这些低级Cython包装器大多数都是自动生成的。BLAS和LAPACK的包装程序主要是使用F2PY从BLAS和LAPACK源文件中解析的类型信息生成的,仅少数例程使用手写类型签名。每个例程的输入和输出类型保存在一个数据文件中,构建时通过读取本文件来生成相应的Cython包装器文件。scipy.special.cython_special中的包装器也是从包含用于包装例程的类型信息的数据文件中生成的。

由于SciPy可以使用LAPACK 3.4.0或更高版本构建,因此Cython包装器仅为在那些在所有受支持的LAPACK版本中保持一致的接口的提供。各种现有BLAS库提供的标准BLAS接口当前无变化,因此SciPy提供的包装程序中通常不需要更改。scipy.special内函数的Cython包装器将引起本包接口的对应改变。

数值优化

所述scipy.optimize子包提供用于求根和求解优化问题的函数。这里我们重点介绍SciPy 1.0新增功能。

线性优化。SciPy 1.0发布了一种新的用于连续线性规划问题的内点优化器linprog,用法为method= 'interior-point’。它实现了商用求解器MOSEK核心算法,可以解决所有90+ 个NETLIB LP基准测试问题。与某些内点法不同,这种自对偶公式确保了不可行或无限问题的适合性。

预求解例程解决了一些琐碎问题,并且以某种方式简化了问题。例如约束紧缩和移除固定变量,自动选择用于消除冗余等式约束的例程以减少由奇异矩阵引起的数值困难。尽管主要求解器是纯Python实现的,但端到端稀疏矩阵支持和SciPy编译的线性系统求解器的大量使用——通常用于预测器-校正器方法这中等号右侧有多项的同一系统——可提供足够的速度来解决有成千上万的变量和约束的问题。

非线性优化:局部最小化minimize函数提供了寻找非线性优化问题局部极小值的统一接口。SciPy的最新版本在minimize中添加了四种新的无约束优化方法:dogleg,trust-ncg,trust-exacttrust-krylov。所有方法都是信任区域方法,它们基于一阶和二阶导数信息建立目标函数的局部模型,在局部“信任区域”内的逼近最佳点,然后进行迭代,直到达到原始目标函数的局部最小值为止。每一种方法都具有独特的特性,使其尤其适合某些特定类型的问题。例如,trust-exact几乎精确地解决信任区域子问题并能快速收敛,但是它需要存储二阶导数Hessian矩阵并在每次迭代时进行因子分解,这可能会不适合解决大规模问题(≥1,000个变量)。作为对比,trust-ncgtrust-krylov非常适合大规模优化问题,因为它们不需要显式存储和分解 Hessian矩阵,而是用近似方式快速的使用二阶导数信息。我们在表1中详细比较了所有最小化方法的特性,这些特性说明了SciPy对数值方法或主题覆盖性的追求。

非线性优化:全局最小化。由于minimize可能返回任何局部最小值,因此某些问题需要使用全局优化例程。新的scipy.optimize.differentialevolution函数是一个随机全局优化器,通过一组候选解的演化求解问题。在每次迭代中,通过组合现有各候选解生成新的试探候选解。若候选试探解代表一种更优,则更新总体。最近,SciPy基准测试套件设计了196个全局优化问题,这些问题将跟踪现有求解器的性能,并评估新求解器的性能以确定其是否值得被包含在软件包中。

表 1:minimize 中的优化方法

-
统计分布

scipy.stats包含超过100个概率分布:96个连续和13个离散的单变量分布,10个多变量分布。本包的实现依赖于一个一致的框架,该框架提供了对随机变量的采样方法,计算累积分布函数(CDF)、概率密度函数(PDF)以及为每个分布拟合参数的方法。通常这些方法依赖于每种分布的特定实现,例如CDF的闭式表达式或采样算法(如果有);若无,则基于通用代码使用默认方法,例如,对PDF进行数值积分以获得CDF。最近添加到scipy.stats的关键分布包括基于直方图的分布scipy.stats.rv_histogram和多项分布scipy.stats.multinomial(用于自然语言处理)。

多项式插值

历史上看,SciPy的严重依赖于由P. Dierckx为单变量插值和数据近似创建的FITPACK Fortran库,但原始的巨型一体化设计、SciPy和FITPACK的交互设计 API既限制了用户,也限制了开发者。

实现一个新的、模块化设计的多项式插值器开始出现在读个版本中。这项工作的目标是用一组代表分段多项式的基本对象实现各种插值器算法,并为用户提供用于构造其他插值器的构造块。

新设计的最低层是代表单变量分段多项式的类:PPoly(SciPy 0.13),BPoly(SciPy 0.13)和BSpline(SciPy 0.19),它们可进行高效的矢量计算、微分、积分和求根。PPoly以幂函数为基在各断点和区间表示分段多项式。BPoly与之类似,但以Bernstein为基表示分段多项式(适合于构造Bézier曲线)。BSpline表示样条曲线,即以B样条为基础的元素的线性组合。

在下一层中,这些多项式类被用来构造常见的数据插值:CubicSpline(SciPy 0.18)构造了一个二次可微的分段三次函数,Akima1DInterpolatorPCHIPInterpolator实现了两个C1连续单调形状保形内插器的经典构造。

测试和基准套件

测试套件。测试驱动的开发是在进行代码更改时管理恐惧和不确定性的一种方法。对于SciPy的每个组件,我们都写了多个小型可执行测试以验证其预期行为。这个测试集合(称为“测试套件”)提高了对库的正确性和准确性的信心,并使我们能够进行代码修改而不会改变所需的行为。根据连续集成的实践经验,在运行测试套件前,所有对SciPy的建议贡献都将暂时与库的master分支合并在一起,必须通过所有测试才能进行永久合并。持续监控单元测试所涵盖的SciPy中的代码行数是我们可以确定更改和正确实现新功能的一种方法。

SciPy测试套件由一个连续集成矩阵编排而成,该矩阵包括分别由Travis CI和AppVeyor管理的POSIX和Windows(32/64位)平台。我们的测试涵盖python版本2.7、3.4、3.5、3.6,并包含使用pyflakespycodestyle进行的代码替换。测试套件中有13,000多个单元测试,这些单元测试是为与pytest框架一起使用而编写的。在图2中,我们展示了使用基于Docker的方法生成的历史测试覆盖率数据。除SciPy v0.14移除了~61,000行已编译代码外,其他相邻新旧版本相比,编译后译代码(C,C ++和Fortran)和Python代码的数量均有所增加,单元测试涵盖的行数也有所增加。根据pytest-cov,Python代码在SciPy 1.0发行点的测试覆盖率为87%。根据gcov,已编译代码(C,C ++和Fortran)的覆盖率仅为45%,但编译后的代码库比该数字所提示的要健壮得多——因为数字并不能正确地反映优质的、经过充分测试的供应商代码;生成的代码,完全覆盖并不现实;不推荐使用的代码,不需要单元测试。代码的文档由CircleCI服务自动生成和发布,以方便评估文档的更改/完整性。

**图 2:SciPy 中的 Python 代码和编译代码量随时间的变化**

基准套件。除了确保通过单元测试外,确保SciPy代码库的性能越来越好也很重要。2015年2月,SciPy的性能开始通过Airspeed Velocity(asv)进行监控。SciPy的run.py脚本可以方便地包装asv函数,以便可以使用单个控制台命令生成时变的基准测试结果。在图3中,我们展示了在大约九年的项目历史中scipy.spatial.cKDTree.query的改进。在基准测试中使用的树是在不应用环形拓扑的情况下生成的(boxsize = None),并通过Airspeed Velocity 0.4使用Python 2.7,NumPy 1.8.2和Cython版本0.27.3、0.21.1和0.18(以提高向后兼容性)进行测试。将cKDTree完全Cython化后性能有显著提升,用C ++重写后获得了进一步的提升。

**图 3:自从cKDTree在 SciPy 1.0版引入后,scipy.spatial.cKDTree.query基准的测试结果**

项目组织和社区

管理

2017年8月3日,SciPy通过了官方管理文件(https://docs.scipy.org/doc/scipy/reference/dev/governance/governance.html)。目前,由18个成员组成的指导委员会通过贡献代码并审查社区的贡献来监督项目的日常开发。委员会成员对项目存储库有 commit权,但是只有在社区没有实质性反对意见的情况下他们才会合并更改。委员会主席Ralf Gommers负责启动对项目方向的半年度技术审查,并向社区总结报告委员会的活动。该项目的终生荣誉总裁Pauli Virtanen在任何事情上都有绝对权威,但仅善意的行动并只在委员会无法达成一致时才行使这一权威。

2017年10月24日,SciPy的官方行为守则获得批准。总的来说,有五项具体准则

  • 对我们社区的所有人开放;
  • 对解决冲突有同情心和耐心;
  • 合作,因为我们彼此依赖才能把库做好;
  • 保持好奇心,因为及早发现问题可以防止严重后果;
  • 注意措辞。

行为守则规定了如何向行为守则委员会报告违规行为,并概述了委员会的回应程序。我们的多样性声明“欢迎并鼓励任何人参与”。

维护者和贡献者

SciPy项目在每隔6个月的发布周期中有约~100个独立参与者。任何有兴趣和技能的人都可以成为贡献者;SciPy开发人员指南(http://scipy.github.io/devdocs/dev/core-dev/index.html)提供了成为贡献者的导引。此外,该项目现有15名活跃的(志愿者)维护者:这些人员负责审查其他人的贡献代码并进行一些其他必要工作以确保软件和项目向前发展。维护者对项目的健康至关重要; 他们的能力和付出在很大程度上决定了该项目的进展速度,决定了是否会吸引更多的贡献者参与其中。任何人都可以成为维护者,因为他们就是从高质量贡献者中滚动选出的。

资助

Open Hub估计SciPy的开发成本超过1000万美元(https://www.openhub.net/p/scipy/estimated_cost)。然而,该项目主要是由研究生、教职员工和企业人员在业余时间开发的,基本上没有资助。少量资助的使用带来了成功:一些会议是由大学和工业界赞助的,Google的“代码之夏”计划支持基础结构和算法工作,早期的文档开发使用了教学经费。但是,来自国家机构、基金会和行业的资助与依赖SciPy的大量重要软件并不相称。用于支持计划、开发、管理和基础架构的更加多元化的资助将有助于让SciPy在国际科学和工业领域保持健康的根基。

下游项目

科学Python生态系统包括大量基于SciPy构建的特定领域软件库的实例,这些实例的开发反过来给基础SciPy库提出建议甚至实施改进。例如,SciPy和Astropy核心库有共同的贡献者,对其中一个的代码库、基础架构或社区有效的代码通常以某种形式转移到另一个中。在代码库级别,binned_statistic功能就是这种跨项目的贡献:它最初是在与Astropy相关的软件包中开发的,随后被放入SciPy。从这个角度来看,SciPy可以促进整个Python科学计算社区的交叉应用。

表 2:1.0 版本后SciPy 路线图项的一个总结

SciPy 子包 更改概要
optimize 几个更高质量的全局优化器
fftpack 减小与 numpy 等效部分的重叠
linalg 减小与 numpy 等效部分的重叠;支持 LAPACK的最新版本
interpolate 新的样条拟合和算术例程;新的透明张量积样条;新的非均匀有理B 样条;B 样条和张量积的细化和粗化
signal 将样条功能迁移至interpolate;二阶部分更新以匹配其他例程
sparse 合并 Sparse 包中的洗漱数组
ndimage 明确“data point”坐标模型的用法,增加其他包装模型
sparse.linalg 为快速 SVD增加 PROPACK 包装器
spatial 增加对旋转矩阵的支持;提高超几何、抛物线圆柱形和球形波函数精度

讨论

SciPy具有强大的开发者社区和庞大的用户群。GitHub流量指标报告,2018年5月14日至2018年5月27日之间(接近撰写本文时),大约有20,000个源网站的唯一访问者,在这段时间内有721个代码库的唯一副本(``克隆'')。当时的开发人员社区由610个独立的源代码贡献者组成,并且在代码库(GitHub页面数据)中接受了超过19,000次提交。

从用户侧看,2017 年,通过Python包索引(PyPI中)网站的SciPy下载量为13096468,通过conda 的默认源的下载量为5776017(https://github.com/ContinuumIO/anaconda-package-data)。考虑到PyPI和conda只是安装SciPy的几种流行方法中的两种,这些数字确定了用户下载总数的下限。SciPy网站(http://www.scipy.org/)是在没有经过同行评审的论文的情况下默认引用的,被引用了3000多次(https://scholar.google.com/scholar?q=SciPy)。SciPy的某些最显着用途或可信度证明包括与LIGO-Virgo的科学合作对引力波的观测。事实上,SciPy在macOS是默认提供的,也用于英特尔的 Python发行版中。GitHub上的47%的机器学习项目中都使用了SciPy (https://github.blog/2019-01-24-the-state-of-the-octoverse-machine-learning/)。

尽管如此,SciPy一直在努力改进。表 2 总结的SciPy路线图(https://docs.scipy.org/doc/scipy-1.0.0/reference/roadmap.htmlhttps://scipy.github.io/devdocs/roadmap.html)是社区维护的不断更新的文档,其中给出了项目改进的一些主要方向以及具体的限制和需要帮助的事项。除了路线图上的项目之外,我们也在努力增加SciPy教程的数量,使其超出我们当前提供的15个部分。我们库中的低级Cython代码(与C级代码交互并暴露给Python使用)可以用某种方法予以现代化,例如迁移到类型化的内存视图以处理NumPy数组。

许多开源项目面临的问题是吸引和留住开发人员。尽管某些人为项目贡献一段时间然后离开是正常的,但是过高的周转可能会令团体记忆的丧失,从而导致重复过去的错误、新代码的API与旧代码不一致、飘忽不定的项目范围。幸运的是,SciPy项目持续吸引着热情而有才干的新开发人员,同时留住了规模虽小但敬业的老兵。在项目的早期阶段有一些贡献者,现在他们仍在讨论错误报告和审查新贡献代码。我们的终生荣誉总裁已在该项目中工作了10多年,仍在积极贡献代码。我们的委员会的主席兼总经理马上迎来他的11周年纪念日。大约有六个左右的活跃开发人员已经稳定地进行了五年或更长时间的贡献。忠于职守的老兵和众多新贡献者的结合,确保了SciPy在保持高质量水平的同时持续发展。

要解决的最后一个重要挑战是如何在不破坏我们一直以来大量使用的算法/ API基础架构的基础上适应GPU和分布式计算。尽管我们仍不清楚整个库中采用这些新兴技术的确切方法,且在1.0版本发布时并未将此事优先考虑,但我们现在已经具体实现了一个子包,允许实验性地使用多个后端,例如在新的scipy.fft中的可GPU处理的数据结构。这将在以后的报告中详细描述。

参考文献

这么长,10000 多字的文章,你竟然读到了最后!一看就是个上进的宝宝,难道你就不想打赏 2 块钱让老朽去买买瓶六味地黄丸么?哈哈哈

相关文章

网友评论

      本文标题:SciPy 1.0:Python科学计算的基本算法

      本文链接:https://www.haomeiwen.com/subject/tnggfhtx.html