SciPy 路线图详细说明#

此路线图主要旨在提供关于每个 SciPy 子模块在新增功能、错误修复等方面最需要什么的高级视图。除了重要的“日常工作”更改之外,它还包含了一些主要新功能的想法——这些想法被标记为“主要新功能”,预计需要投入大量专门的精力。此路线图中未提及的事项并不一定不重要或超出范围,但我们(SciPy 开发者)希望向用户和贡献者提供一个清晰的图景,说明 SciPy 的发展方向以及最需要帮助的地方。

注意

这是详细的路线图。一个非常高级的概述,只包含最重要的想法,请参见 SciPy 路线图.

通用#

此路线图将随着 SciPy 的发展而不断演变。更新可以作为拉取请求提交。对于大型或破坏性更改,您可能需要先在 scipy-dev 邮件列表中进行讨论。

API 更改#

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

测试覆盖率#

过去几年中添加的代码的测试覆盖率相当不错,我们也力求对所有新添加的代码进行高覆盖率测试。然而,仍然有相当一部分旧代码的覆盖率很低。将这些代码提升到当前标准可能不现实,但我们应该填补最大的漏洞。

除了覆盖率之外,还有正确性问题——旧代码可能有一些测试提供了不错的语句覆盖率,但这并不一定说明代码是否按预期工作。因此,需要对部分代码进行代码审查(特别是 statssignalndimage)。

文档#

文档状况良好。应该继续扩展当前的文档字符串——添加示例、参考资料和更详细的解释。大多数模块在参考指南中都有一个教程,这是一个很好的入门介绍,但有一些教程缺失或不完整——这应该得到解决。

基准测试#

基于 asv 的基准测试系统状况良好。添加新的基准测试非常容易,但运行基准测试并不直观。简化这一过程是一个优先事项。

Cython 的使用#

应该移除 Cython 中使用 NumPy 数组的旧语法,并用 Cython 内存视图替换。

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

使用 Pythran#

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

使用久经考验的 Fortran 库#

SciPy 的成功很大程度上归功于它依赖于封装成熟的 Fortran 库(QUADPACK、FITPACK、ODRPACK、ODEPACK 等)。其中一些库运行良好,而另一些则不太好。我们应该针对维护工作量、功能以及(可能部分)替代方案的存在(包括 SciPy 内部)来审计我们对这些库的使用情况。

持续集成#

持续集成目前涵盖 32/64 位 Windows、x86-64/arm 上的 macOS、x86 上的 32/64 位 Linux 以及 aarch64 上的 Linux - 以及我们依赖项和构建发布质量轮子的各种版本。由于需要支持大量配置,并且一些 CI 作业需要大修,因此 CI 的可靠性最近(2023 年上半年)一直不佳。我们的目标是通过删除我们删除该构建系统后剩余的基于 distutils 的作业,并使 CI 作业中的配置集更加正交来减少构建时间。

二进制文件的大小#

SciPy 二进制文件相当大(例如,1.7.3 的解压缩的 manylinux 轮子在 PyPI 上为 39 MB,安装后为 122 MB),这可能会带来问题 - 例如,在 AWS Lambda 中使用,AWS Lambda 的大小限制为 250 MB。我们的目标是尽可能降低二进制文件的大小;在添加新的编译扩展时,需要进行检查。在 multibuild 中剥离调试符号可能需要改进(参见 此问题)。应该努力尽可能地精简,不要添加新的大型文件。将来,正在考虑(非常初步)并且可能有所帮助的事情包括将捆绑的 libopenblas 分开以及删除对 long double 的支持。

模块#

cluster#

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

constants#

此模块基本上已经完成,维护量低,没有开放问题。

fft#

该模块状态良好。

积分#

常微分方程求解器需要。

  • 文档质量较差,需要修复。

  • SciPy 1.0.0 中添加了一个新的常微分方程求解器接口 (solve_ivp)。将来我们可以考虑 (软) 弃用旧的 API。

数值积分函数状态良好。可以添加对复值函数积分和多个区间积分的支持(参见 gh-3325)。

插值#

样条拟合:我们需要具有更好用户控制的样条拟合例程。这包括

  • 用户可选择的平滑标准替代方案(手动、交叉验证等);gh-16653 在这方面迈出了第一步;

  • 几种结点放置策略,包括手动和自动(使用 Dierckx、de Boor 等算法)。

一旦我们拥有一个功能相当完整的集合,我们就可以开始长期审视久负盛名的 FITPACK Fortran 库的未来,该库目前是 SciPy 中构建平滑样条的唯一方法。

可扩展性和性能:对于基于 FITPACK 的功能,数据大小受 32 位 Fortran 整数大小限制(对于非 ILP64 构建)。对于 N 维散点插值器(基于 QHull)和 N 维规则网格插值器,我们需要检查大型数据集上的性能,并在不足之处进行改进(gh-16483 在这方面取得了进展)。

新功能的想法:可以添加 NURBS 支持。

io#

wavfile

  • 将支持 PCM 浮点数,对于其他任何内容,请使用 audiolab 或其他专门的库。

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

其他子模块(matlab、netcdf、idl、harwell-boeing、arff、矩阵市场)状态良好。

linalg#

scipy.linalg 状态良好。

需要

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

  • get_lapack_funcs 应始终使用 flapack

  • 包装更多 LAPACK 函数

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

新功能的想法

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

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

BLAS 和 LAPACK

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

  1. 我们的发布的轮子现在附带 OpenBLAS,这是目前唯一可行的性能选项(ATLAS 太慢,MKL 由于许可问题不能作为默认选项,Accelerate 支持被放弃,因为 Apple 不再更新 Accelerate)。然而,OpenBLAS 并不稳定,有时它的版本会破坏某些功能,并且在多线程方面存在问题(目前是使用 SciPy 与 PyPy3 的唯一问题)。我们至少需要更好的支持来调试 OpenBLAS 问题,以及有关如何使用它构建 SciPy 的更详细文档。一个选择是使用 BLIS 作为 BLAS 接口(参见 numpy gh-7372)。

  2. 在 SciPy 1.2.0 中,我们将支持的 LAPACK 最低版本提升至 3.4.0。现在我们已经放弃了 Python 2.7,我们可以进一步提高这个版本(MKL + Python 2.7 之前是 >3.4.0 的阻碍),并开始添加对 LAPACK 中新功能的支持。

misc#

scipy.misc 将被移除作为公共模块。其中的大多数函数已被移至其他子模块或已弃用。剩下的几个函数

  • derivative, central_diff_weight : 将被移除,可能用更全面的数值微分功能替换。

  • ascent, face, electrocardiogram : 将被移除或移至相应的子包(例如 scipy.ndimage, scipy.signal)。

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#

总体而言,这个模块状况良好。在 1.2.0 中添加了两个优秀的全局优化器;大规模优化器仍然是一个可以填补的空白。其他需要的东西

  • linprog 中添加更多功能的想法(例如整数约束),请参见 gh-9269

  • 向基准测试套件添加功能,以便更容易地比较结果(例如,使用摘要图)。

  • 在文档中弃用 fmin_* 函数,minimize 是首选。

  • scipy.optimize 有一套广泛的基准测试,用于评估全局优化器的准确性和速度。这使得能够添加新的优化器(shgodual_annealing),其性能明显优于现有优化器。然而,optimize 基准测试系统本身速度缓慢且难以使用;我们需要使其更快,并使其更容易通过绘制性能曲线来比较优化器的性能。

signal#

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

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

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

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

二阶截断: 使 SOS 滤波与现有方法具有同等的能力。这包括 ltisys 对象、一个 lfiltic 等效项以及在其他滤波器表示之间进行数值稳定的转换。由于其数值稳定性,SOS 滤波器可以被视为 ltisys 对象的默认滤波方法。

小波: 目前存在的代码意义不大。目前只有连续小波 - 决定是完全重写还是移除它们。离散小波变换不在范围内 (PyWavelets 对这些变换做得很好)。

稀疏#

稀疏矩阵格式大多功能齐全,但主要问题是它们的行为类似于 numpy.matrix (将在 NumPy 中某个时候弃用)。

我们想要的是行为类似于 numpy.ndarray 的稀疏数组。SciPy 1.8.0 中添加了对一组新类 (csr_array 等) 的初始支持,并在 1.12.0 中稳定,当时添加了数组的构造函数。对 1-D 数组的支持预计将在 1.13.0 中实现。

稀疏数组支持的下一步计划

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

    • CSR 一维支持最小值-最大值、索引和算术运算。

  • 帮助其他库将稀疏矩阵转换为稀疏数组。创建转换指南和有用的脚本以标记需要进一步检查的代码。NetworkX、scikit-learn 和 scikit-image 正在进行或已完成转换为稀疏数组。

  • 在稀疏数组代码成熟后(大约 1 个发布周期?),添加对稀疏矩阵的弃用警告。

  • 与 NumPy 合作弃用/删除 numpy.matrix

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

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

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

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

一个替代方案(更雄心勃勃,尚不清楚是否会实现)正在 pydata/sparse 中开发。为了支持这项工作,我们的目标是在所有接受稀疏数组的函数中支持 PyData Sparse。对 pydata/sparsescipy.sparse.linalgscipy.sparse.csgraph 中的支持基本完成。

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

sparse.csgraph#

该模块状态良好。

sparse.linalg#

对于 _arpacklobpcg,存在大量未解决的问题。 _propack 是 1.8.0 中的新功能,其稳定性尚待观察。

_isolve:

  • 回调关键字不一致

  • tol 关键字已损坏,应为相对容差

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

_dsolve:

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

  • 添加许可证兼容的稀疏 QR

  • 改进与 SuiteSparse UMFPACK 的接口

  • 添加与 SuiteSparse CHOLMOD 和 SPQR 的接口

空间#

QHull 包装器状态良好,KDTree 也是如此。

正在用 C++ 重写 spatial.distance 度量 - 这将提高性能,使行为(例如,对于各种非 float64 输入数据类型)更加一致,并修复一些度量数学实现定义中剩余的问题。

特殊#

尽管仍有许多函数需要改进精度,但可能唯一的问题是超几何函数、抛物柱面函数和球面波函数。处理此问题的三种可能方法

  1. 获得良好的双精度实现。对于抛物柱面函数(正在进行中)是可以实现的。我认为对于超几何函数也是可能的,尽管可能无法及时完成。对于球面波函数,使用当前理论无法实现。

  2. 移植 Boost 的任意精度库,并在后台使用它来获得双精度精度。这可能需要作为超几何函数的权宜之计;使用任意精度的想法之前曾由 @nmayorov 和 gh-5349 中提出。对于球面波函数可能需要,这可以重复使用:radelman/scattering.

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

统计#

scipy.stats 子包旨在提供基本统计方法,这些方法可能在标准统计文本中有所介绍,例如 Johnson 的“Miller & Freund’s Probability and Statistics for Engineers”,Sokal & Rohlf 的“Biometry”,或 Zar 的“Biostatistical Analysis”。它不寻求复制下游包(例如 StatsModels、LinearModels、PyMC3)的先进功能;相反,它可以提供一个坚实的基础,下游包可以以此为基础构建。(请注意,这些只是粗略的指南,而不是严格的规则。“高级”是一个定义不明确且主观的术语,并且“高级”方法也可能包含在 SciPy 中,尤其是在没有其他广泛使用且得到良好支持的包涵盖该主题的情况下。还要注意,与下游项目的一些重复是不可避免的,也不一定是坏事。)

除了SciPy路线图中描述的内容外,以下改进将有助于SciPy更好地发挥其作用。

  • 添加基本且广泛使用的假设检验,例如

    • 事后检验(例如Dunnett检验)

    • 各种类型的方差分析(ANOVA)

      • 双因素方差分析(单次重复、均匀重复次数、可变重复次数)

      • 多因素方差分析(即概括双因素方差分析)

      • 嵌套方差分析

      • 协方差分析(ANCOVA)

    此外,提供用于实现假设检验的基础设施。

  • 添加用于元分析的额外工具

  • 添加用于生存分析的工具

  • 加快分布的随机变量采样(方法rvs),在适当的情况下利用scipy.stats.sampling

  • 扩展QMC功能和性能

  • 增强连续概率分布的fit方法

    • 扩展拟合选项,包括

      • 最大乘积间距

      • L-矩/概率加权矩方法

    • 在结果中包含拟合优度度量

    • 处理删失数据(例如合并gh-13699

  • 实现其他广泛使用的连续和离散概率分布,例如混合分布。

  • 改进SciPy概率分布提供的核心计算,使其能够稳健地处理各种参数值。具体来说,将scipy.special中使用的Fortran库CDFLIB中的许多PDF和CDF方法替换为Boost实现,如gh-13328中所示。

此外,我们应该

  • 继续努力使statsstats.mstats的函数签名更加一致,并添加测试以确保这种情况仍然存在。

  • 改进统计检验:返回检验统计量的置信区间,并在计算上可行的情况下实现精确的p值计算 - 考虑可能存在的联系。