SciPy 详细路线图#

本路线图的大部分旨在就每个 SciPy 子模块在新功能、错误修复等方面最需要什么提供高层视图。除了重要的“照常营业”变更外,它还包含主要新功能的想法——这些功能已特别标记,预计需要投入大量的专门工作。本路线图中未提及的事项不一定不重要或超出范围,但我们(SciPy 开发人员)希望向我们的用户和贡献者清晰地展示 SciPy 的发展方向以及最需要帮助的地方。

注意

这是详细的路线图。一个仅包含最重要想法的非常高层的概述是SciPy 路线图

通用#

本路线图将与 SciPy 一同发展。更新可以通过拉取请求提交。对于大型或破坏性的更改,您可能希望首先在 scipy-dev 论坛上讨论。

API 变更#

总的来说,我们希望尽可能地发展 API,以消除已知的缺陷,但也要尽可能地保持向后兼容性

测试覆盖率#

过去几年添加的代码的测试覆盖率相当好,我们致力于为所有新添加的代码实现高覆盖率。然而,仍有大量旧代码的覆盖率很差。将其提升到当前标准可能不现实,但我们应该堵住最大的漏洞。

除了覆盖率,还有一个正确性问题——旧代码可能有一些提供良好语句覆盖率的测试,但这不一定能说明代码是否名副其实。因此,需要对代码的某些部分(特别是statssignalndimage)进行代码审查。

文档#

文档状况良好。应继续扩展当前的 docstrings——添加示例、参考文献和更好的解释。大多数模块在参考指南中也有一个很好的入门教程,但有几个教程缺失或不完整——这应该得到修复。

基准测试#

基于 asv 的基准测试系统状况良好。添加新的基准测试相当容易,但运行基准测试却不是很直观。使其更容易是优先事项。

Cython 的使用#

Cython 旧的 NumPy 数组使用语法应该被移除并替换为 Cython memoryviews。

由 Cython 代码构建的扩展模块的二进制文件大小很大,编译时间很长。我们应该尽可能地合并扩展模块(例如,stats._boost 现在包含许多扩展模块),并将 Cython 的使用限制在它是最佳选择的地方。请注意,scipy.special 中正在进行 Cython 到 C++ 的转换。

Pythran 的使用#

Pythran 仍然是一个可选的构建依赖项,可以使用 -Duse-pythran=false 禁用。目标是使其成为硬依赖项——为此,必须明确维护负担足够低。

Fortran 库的使用#

SciPy 的成功很大程度上归功于对成熟 Fortran 库(QUADPACK、FITPACK、ODRPACK、ODEPACK 等)的封装。这些库所用的 Fortran 77 语言难以维护,且 Fortran 的使用存在许多问题;例如,它使我们的 wheel 构建更难维护,反复给支持 macOS arm64 和 Windows on Arm 等新平台带来问题,并对 Pyodide 的 SciPy 支持造成了极大的困扰。我们的目标是通过用其他语言编写的代码替换其功能,从而从 SciPy 中移除所有 Fortran 代码。此目标的进展在 gh-18566 中跟踪。

持续集成#

持续集成目前涵盖 32/64 位 Windows、x86-64/arm 上的 macOS、x86 上的 32/64 位 Linux 和 aarch64 上的 Linux,以及一系列版本的依赖项和构建发布质量的 wheel。最近(2023 年上半年)CI 的可靠性不佳,原因是要支持的配置数量庞大以及一些 CI 作业需要进行大修。我们计划在放弃 distutils 构建系统时,通过移除剩余的基于 distutils 的作业来缩短构建时间,并使 CI 作业中的配置集更加正交。

二进制文件大小#

SciPy 二进制文件相当大(例如,1.7.3 版本的未解压 manylinux wheel 在 PyPI 上为 39 MB,安装后为 122 MB),这可能会带来问题——例如在 AWS Lambda 中使用,它有 250 MB 的大小限制。我们的目标是尽可能保持二进制文件大小最小;在添加新的编译扩展时,需要检查这一点。multibuild 中调试符号的剥离或许可以改进(参见此问题)。应努力在可能的情况下进行精简,并且不添加新的大文件。将来,正在考虑(非常初步地)且可能有所帮助的是分离捆绑的 libopenblas 并移除对 long double 的支持。

模块#

cluster#

dendrogram 需要重写,它有许多难以修复的开放问题和功能请求。

constants#

此模块仅需定期更新数值。

differentiate#

添加此模块时,其范围将被限定。目标是提供黑盒函数的基本微分,而不是复制现有微分工具的所有功能。考虑到这一点,未来的工作包括:

  • 改进对接受额外参数的调用体的支持(例如,向 jacobianhessian 添加 *args)。请注意,由于当数组元素对应的计算收敛时,这些元素会被消除,因此这不是微不足道的。

  • 改进 scipy.differentiate.hessian 的实现:不使用一阶微分的链式调用,而是使用二阶微分模板。

  • 考虑添加一个使用相对步长的选项。

  • 考虑推广这种方法以使用“多项式外推”;即,不从最少数量的函数评估中估计给定阶数的导数,而是使用最小二乘法来提高对数值噪声的鲁棒性。

fft#

此模块状况良好。

integrate#

  • 完成新的 cubature 函数的功能集,并添加专为一维积分设计的接口。

  • special 迁移用于生成求积规则点和权重的函数,提高其可靠性,并添加对其他重要规则的支持。

  • 完成 solve_ivp 的功能集,包括 odeint 接口的所有功能。

  • 优雅地淘汰被取代的函数和类。

interpolate#

FITPACK 替换

我们需要完成提供 FITPACK Fortran 库的功能等价物。目标是以模块化的方式重新实现 FITPACK 巨石的算法内容,以允许更好的用户控制和可扩展性。为此,我们需要

  • 一维样条:将周期样条拟合添加到 make_splrep 函数中。

  • 二维样条:为散点和网格数据提供 BivariateSpline 类家族的功能替换。

一旦我们拥有了功能完整的替换集,我们就可以优雅地淘汰对 FITPACK 的使用。

新功能的想法

  • make_smoothing_spline 中添加构造具有可变节点数的平滑样条的能力。目前,make_smoothing_spline 总是使用所有数据点作为节点向量。

  • 尝试用户可选择的平滑标准:添加 P 样条惩罚形式,以补充 make_smoothing_spline 的二阶导数惩罚和 make_splrep 的三阶导数跳跃。

  • 研究独立变量批次样条构造的矢量化方法。这种类型的功能已由 scipy.stats 开发人员请求。

  • 允许为样条拟合指定边界条件。

  • 研究 FITPACK 库在 Fortran 中提供但从未暴露给 Python 接口的受约束样条拟合问题。

  • 如果用户有足够兴趣,可以添加 NURBS 支持。

可扩展性和性能

我们需要检查大型数据集上的性能,并在不足之处进行改进。这对于常规网格 N 维插值器和基于 QHull 的散点 N 维插值器都很重要。对于后者,我们还需要研究是否可以改进 QHull 库的 32 位整数限制。

io#

wavfile

  • 将支持 PCM 浮点数,其他任何格式请使用 audiolab 或其他专业库。

  • 如果数据无法理解,则抛出错误而不是警告。

其他子模块(matlab、netcdf、idl、harwell-boeing、arff、matrix market)状况良好。

linalg#

scipy.linalg 状况良好。

所需

  • 减少与 numpy.linalg 的函数重复,使 API 保持一致。

  • get_lapack_funcs 应该始终使用 flapack

  • 封装更多 LAPACK 函数

  • LU 分解函数太多,移除一个

新功能的想法

  • 在 Cython BLAS 和 LAPACK 中添加类型通用包装器

  • 将许多线性代数例程转换为 gufuncs

  • 完成对批量操作的支持(参见 gh-21466

BLAS 和 LAPACK

scipy.linalg 中到 BLAS 和 LAPACK 的 Python 和 Cython 接口是 SciPy 提供的最重要的功能之一。总的来说,scipy.linalg 状况良好,但我们可以进行一些改进。

  1. 添加对 ILP64 (64位) BLAS 和 LAPACK 的支持(参见 gh-21889

  2. 统一两组低级 BLAS/LAPACK 包装器,可能放弃基于 f2py 的包装器(参见 gh-20682

  3. 改进并记录我们从 SciPy 内部的 C 和 C++ 代码链接到 BLAS 和 LAPACK 的各种方式(参见 gh-20002gh-21130

misc#

所有功能已从 scipy.misc 中移除,该命名空间本身最终也将被移除。

ndimage#

底层的 ndimage 是一个强大的插值引擎。用户通常预期以下两种模型之一:一种是像素模型,其中 (1, 1) 元素中心位于 (0.5, 0.5);另一种是数据点模型,其中值定义在网格上的点。随着时间的推移,我们越来越确信数据点模型定义更清晰,实现更容易,但这一点应在文档中明确说明。

更重要的是,SciPy 仍然实现的是这种数据点模型的一种变体,其中轴的两个极端的数据点在周期性包裹模式下共享一个空间位置。例如,在一维数组中,x[0]x[-1] 将共置。然而,一个非常常见的用例是信号是周期的,沿轴的第一个和最后一个元素之间具有相等的间距(而不是零间距)。针对此用例的包裹模式已在 gh-8537 中添加,接下来插值例程应更新以使用这些模式。这将解决包括 gh-1323、gh-1903、gh-2045 和 gh-2640 在内的几个问题。

形态学接口需要标准化

  • 二值膨胀/腐蚀/开运算/闭运算接受“结构”参数,而其灰度等效操作接受大小(必须是元组,而不是标量)、足迹或结构。

  • 标量应该可以接受作为大小,等同于为每个轴提供相同的值。

  • 对于二值膨胀/腐蚀/开运算/闭运算,结构元素是可选的,而对于灰度操作,它是强制的。灰度形态学操作应获得相同的默认值。

  • 其他过滤器也应尽可能采用该默认值。

odr#

此模块状况良好,尽管可能需要更多的维护。此处没有重大计划或愿望。

optimize#

我们致力于持续改进本模块提供的优化器集合。对于大规模问题,最先进的技术不断发展,我们旨在通过利用 HiGHS 和 PRIMA 等领域特定库的实现来跟进。未来工作的其他领域包括:

  • 改进现有优化器的接口(例如 shgo)。

  • 改进基准测试系统的可用性,并添加更易于比较结果的功能(例如摘要图)。

signal#

卷积和相关:(相关函数包括 convolve, correlate, fftconvolve, convolve2d, correlate2d 和 sepfir2d。)消除与 ndimage(及其他地方)的重叠。从 numpy, scipy.signalscipy.ndimage(以及我们找到它们的任何其他地方),为 1D、2D 和 nD 卷积和相关选择“一流”的实现,将实现放在某个地方,并在整个 SciPy 中一致使用。

B 样条:(相关函数包括 gauss_spline, cspline1d, qspline1d, cspline2d, qspline2d, cspline1d_eval 和 spline_filter。)将优秀部分移至 interpolate(并进行适当的 API 更改以匹配 interpolate 中的处理方式),并消除任何重复。

滤波器设计:合并 firwinfirwin2,以便可以移除 firwin2

连续时间线性系统:进一步提高 ltisys 的性能(减少不同表示之间内部转换)。填补 lti 系统转换函数的空白。

二阶节:使 SOS 滤波与现有方法具有同等能力。这包括 ltisys 对象、等效的 lfiltic,以及与其他滤波器表示之间数值稳定的转换。SOS 滤波器可被视为 ltisys 对象的默认滤波方法,因为它们具有数值稳定性。

sparse#

稀疏矩阵格式的功能大部分已经完善,但主要问题是它们行为类似于 numpy.matrix(该功能在 NumPy 中最终会被废弃)。

我们想要的是行为类似于 numpy.ndarray 的稀疏数组。SciPy 1.8.0 中添加了新类集(csr_array 等)的初步支持,并在 1.12.0 中通过数组构造函数、1.14.0 中的 1D 数组支持和 1.15.0 中的 1D 索引得到了稳定。稀疏数组代码库现在支持所有稀疏矩阵功能,此外还支持 1D 数组以及 nD 数组的第一步。有一个转换指南可以帮助用户和库将其代码转换为稀疏数组。

稀疏数组转换的下一步

  • 将稀疏数组 API 扩展到 nD 数组。
    • 支持 COO、CSR 和 DOK 格式。

    • 1.15 版本中存在一些 COO 功能。

  • 在稀疏格式可以有效实现广播的操作中引入对广播的支持。

  • 帮助其他库从稀疏矩阵转换为稀疏数组。NetworkX、dipy、scikit-image、pyamg、cvxpy 和 scikit-learn 正在进行或已完成转换为稀疏数组。

  • 为稀疏矩阵添加弃用警告。

  • 与 NumPy 合作,废弃/移除 numpy.matrix

  • 弃用并随后移除稀疏矩阵,转而使用稀疏数组。

  • 开始构造函数名称的 API 变更(diagsblock 等)
    • 注:总的来说,构造函数将经历两次名称变更。第一次是从矩阵创建移动到新的数组创建函数(即 eye -> eye_array)。然后第二次是稀疏矩阵移除后,将名称更改为与 array_api 名称匹配(即 eye_arrayeye)。我们将长期保留 *_array 版本作为(可能隐藏的)别名。

  • 添加与 array_api 名称匹配的构造函数名称。

  • 废弃过渡构造函数名称。

pydata/sparse 中正在制定一个替代(更雄心勃勃,但尚不清楚是否会实现)计划。为了支持这项工作,我们的目标是在所有接受稀疏数组的函数中支持 PyData Sparse。scipy.sparse.linalgscipy.sparse.csgraphpydata/sparse 的支持已基本完成。

关于不同的稀疏矩阵格式:它们有很多。这些应该保留,但改进/优化应该投入到 CSR/CSC 中,它们是首选格式。LIL 可能是一个例外,它本身效率低下。如果 DOK 扩展到支持 LIL 当前提供的所有操作,则可以放弃它。

sparse.csgraph#

此模块状况良好。

sparse.linalg#

_arpacklobpcg 有大量的开放问题。

_isolve:

  • callback 关键词不一致

  • tol 关键词已损坏,应该是相对容差

  • Fortran 代码不可重入(但我们不解决,或许可以从 PyKrilov 重用)

_dsolve:

  • 添加兼容许可的稀疏 Cholesky 或不完全 Cholesky

  • 添加兼容许可的稀疏 QR

  • 改进与 SuiteSparse UMFPACK 的接口

  • 添加与 SuiteSparse CHOLMOD 和 SPQR 的接口

spatial#

QHull 封装器状况良好,KDTree 亦是如此。

spatial.distance 指标的 C++ 重写正在进行中——这应该会提高性能,使行为(例如,对于各种非 float64 输入 dtype)更加一致,并修复一些关于某些指标实现的数学定义的剩余问题。

special#

尽管仍有许多函数在精度上需要改进,但可能唯一的拦路虎是超几何函数、抛物线柱函数和扁球波函数。有三种可能的处理方法:

  1. 获取良好的双精度实现。这对于抛物线柱函数是可行的(正在进行中)。我认为对于超几何函数也是可能的,尽管可能无法及时完成。对于扁球波函数,以目前的理论来说这是不可能的。

  2. 移植 Boost 的任意精度库并在后台使用它来获得双精度准确性。这可能作为超几何函数的一个权宜之计;之前 @nmayorov 和在 gh-5349 中都曾建议过使用任意精度的想法。对于扁球波函数可能很有必要,这可以重用:radelman/scattering

  3. 在文档中添加关于现有实现限制的明确警告。

stats#

scipy.stats 子包旨在提供基本统计方法,这些方法可能涵盖在标准统计教材中,例如 Johnson 的《Miller & Freund's Probability and Statistics for Engineers》、Sokal & Rohlf 的《Biometry》或 Zar 的《Biostatistical Analysis》。它不寻求复制下游包(例如 StatsModels、LinearModels、PyMC3)的高级功能;相反,它可以提供一个坚实的基础,供它们在其上构建。(请注意,这些是粗略的指导方针,而非严格的规则。“高级”是一个定义模糊且主观的术语,SciPy 中也可能包含“高级”方法,特别是如果没有其他广泛使用且受支持的包涵盖该主题。另请注意,与下游项目的一些重复是不可避免的,并且不一定是坏事。)

以下改进将帮助 SciPy 更好地履行这一职责。

  • 改进统计检验:包括生成置信区间的方法,并在计算可行的情况下实现精确和随机的 p 值计算——考虑平局的可能性。

  • 扩展新的单变量分布基础设施,增加对离散分布和圆形连续分布的支持。在新基础设施下添加一系列最广泛使用的统计分布,进行严格的准确性测试并记录结果。使用户能够创建利用新基础设施的自定义分布。

  • 改进多变量分布基础设施,以确保一致的 API、彻底的测试和完整的文档。

  • 继续使函数的 API 更加一致,对批量计算、NaN 策略和 dtype 保留提供标准支持。