详细的 SciPy 路线图#
这个路线图的大部分内容旨在提供一个高层次的视角,了解每个SciPy子模块在新增功能、错误修复等方面最需要什么。除了重要的“常规业务”变更外,它还包含了一些主要新功能的构想——这些都被特别标记,并预计需要大量的专门努力。未在此路线图中提及的内容并不一定不重要或超出范围,然而我们(SciPy开发者)希望向我们的用户和贡献者提供一个清晰的画面,展示SciPy的发展方向以及最需要帮助的地方。
备注
这是详细的路线图。一个非常高层次的概述,只包含最重要的想法,请参见 SciPy 路线图。
一般#
此路线图将与 SciPy 一起发展。更新可以通过提交拉取请求来进行。对于大型或破坏性的更改,您可能希望首先在 scipy-dev 论坛上讨论这些更改。
API 变更#
总的来说,我们希望尽可能地改进API以去除已知的瑕疵,但尽可能在不破坏向后兼容性的前提下。
测试覆盖率#
过去几年新增代码的测试覆盖率相当不错,我们致力于为所有新增代码实现高覆盖率。然而,仍有大量旧代码的覆盖率较差。将这些代码提升到当前标准可能不太现实,但我们应该填补最大的漏洞。
除了覆盖率之外,还有正确性的问题——旧代码可能有一些测试提供了不错的语句覆盖率,但这并不一定说明代码是否按照其描述的功能工作。因此,对代码的某些部分(特别是 stats、signal 和 ndimage)进行代码审查是必要的。
文档#
文档状况良好。扩展当前的文档字符串 - 添加示例、引用和更好的解释 - 应继续进行。大多数模块在参考指南中也有一个很好的介绍性教程,然而有一些教程缺失或不完整 - 这应该得到修正。
基准测试#
基于 asv 的基准测试系统处于合理状态。添加新的基准测试非常容易,然而运行基准测试并不十分直观。简化这一过程是优先事项。
使用 Cython#
Cython 使用 NumPy 数组的旧语法应被移除,并替换为 Cython 内存视图。
由 Cython 代码构建的扩展的二进制大小较大,编译时间也较长。我们应该尽可能地合并扩展模块(例如,stats._boost 现在包含许多扩展模块),并将 Cython 的使用限制在它是最佳选择的场合。请注意,在 scipy.special 中,Cython 向 C++ 的转换正在进行中。
使用 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 - 还包括一系列依赖版本和构建发布质量的wheels。最近(2023年上半年)CI的可靠性不佳,这是由于需要支持的大量配置以及一些CI作业需要彻底检修。我们的目标是当我们放弃该构建系统并使CI作业中的配置集更加正交时,通过移除剩余的基于distutils的作业来减少构建时间。
二进制文件的大小#
SciPy 二进制文件相当大(例如,1.7.3 版本的未压缩 manylinux 轮在 PyPI 上为 39 MB,安装后为 122 MB),这可能会带来问题——例如在 AWS Lambda 中使用,其大小限制为 250 MB。我们的目标是尽可能保持二进制文件的大小;在添加新的编译扩展时,需要检查这一点。multibuild 中的调试符号剥离可能可以改进(参见 此问题)。应尽可能减少文件大小,并且不添加新的大型文件。未来,正在考虑(非常初步地)并可能有所帮助的事情包括分离捆绑的 libopenblas 并移除对 long double 的支持。
模块#
集群#
dendrogram 需要重写,它有许多难以修复的开放问题和功能请求。
常量#
该模块基本完成,维护需求低且没有未解决的问题。
fft#
这个模块状态良好。
整合#
ODE 求解器所需:
文档非常糟糕,需要修复
在 SciPy 1.0.0 中添加了一个新的 ODE 求解器接口 (
solve_ivp)。未来我们可以考虑(软性)弃用旧的 API。
数值积分函数的状态良好。可以添加对复值函数积分和积分多个区间(参见 gh-3325)的支持。
插值#
样条拟合:我们需要具有更好用户控制的样条拟合例程。这包括
平滑标准的用户可选替代方案(手动、交叉验证等);gh-16653 在这方面迈出了第一步;
几种结点放置策略,包括手动和自动(使用Dierckx、de Boor等算法)。
一旦我们有了一个功能相对完整集,我们就可以开始深入研究受人尊敬的 FITPACK Fortran 库的未来,目前这是在 SciPy 中构建平滑样条曲线的唯一方法。
可扩展性和性能: 对于基于FITPACK的功能,数据大小受限于32位Fortran整数大小(对于非ILP64构建)。对于N-D散点插值器(基于QHull)和N-D规则网格插值器,我们需要在大数据集上检查性能,并在不足之处进行改进(gh-16483在这方面取得了进展)。
新功能的想法: 可以添加 NURBS 支持。
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 中添加类型泛型包装器
将许多线性代数例程转换为广义函数
BLAS 和 LAPACK
scipy.linalg 中的 Python 和 Cython 对 BLAS 和 LAPACK 的接口是 SciPy 提供的最重要功能之一。总体来说,scipy.linalg 的状态良好,但我们仍可以进行多项改进:
库支持。我们发布的轮子现在附带了 OpenBLAS,目前这是唯一可行的性能选项(ATLAS 太慢,MKL 由于许可问题不能作为默认选项,Accelerate 支持被放弃,因为 Apple 不再更新 Accelerate)。尽管如此,OpenBLAS 并不非常稳定,有时它的发布会破坏东西,并且在多线程方面存在问题(目前使用 PyPy3 运行 SciPy 的唯一问题)。我们至少需要更好的 OpenBLAS 问题调试支持,以及如何使用它构建 SciPy 的更好文档。一个选择是使用 BLIS 作为 BLAS 接口(参见 numpy gh-7372)。
支持更新的 LAPACK 特性。在 SciPy 1.2.0 中,我们将支持的 LAPACK 最低版本提高到 3.4.0。现在我们放弃了 Python 2.7,我们可以进一步提高该版本(MKL + Python 2.7 之前是 >3.4.0 的阻碍),并开始添加对 LAPACK 新特性的支持。
杂项#
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#
这个模块状态良好,尽管它可能需要更多的维护。这里没有重大的计划或愿望。
优化#
总的来说,这个模块状态良好。在1.2.0版本中添加了两个优秀的全局优化器;大规模优化器仍然是一个可以填补的空白。其他需要的东西包括:
许多关于
linprog中增加功能的建议(例如整数约束),参见 gh-9269。为基准测试套件添加功能,以便更容易地比较结果(例如,使用汇总图表)。
在文档中弃用
fmin_*函数,推荐使用minimize。scipy.optimize拥有一套广泛的基准测试,用于评估全局优化器的准确性和速度。这使得能够添加新的优化器(shgo和dual_annealing),其性能显著优于现有的优化器。然而,optimize基准测试系统本身运行缓慢且难以使用;我们需要使其更快,并通过绘制性能概况来更容易地比较优化器的性能。
信号#
卷积和相关: (相关函数有 convolve, correlate, fftconvolve, convolve2d, correlate2d, 和 sepfir2d.) 消除与 ndimage (及其他地方) 的重叠。从 numpy, scipy.signal 和 scipy.ndimage (以及我们找到的任何其他地方) 中,选择 1-D, 2-D 和 n-D 卷积和相关的“最佳类”,将其实现放在某个地方,并在整个 SciPy 中一致使用。
B样条:(相关的函数有 gauss_spline, cspline1d, qspline1d, cspline2d, qspline2d, cspline1d_eval, 和 spline_filter。)将好的部分移动到 interpolate`(并进行适当的API更改以匹配 `interpolate 中的做法),并消除任何重复。
滤波器设计:合并 firwin 和 firwin2 以便可以移除 firwin2。
连续时间线性系统: 进一步提高 ltisys 的性能(减少不同表示之间的内部转换)。填补 lti 系统转换函数中的空白。
二阶节段: 使SOS滤波与现有方法同样有效。这包括ltisys对象、一个等效于`lfiltic`的函数,以及在其他滤波表示之间进行数值稳定的转换。SOS滤波可以被视为ltisys对象的默认滤波方法,因为它们的数值稳定性。
小波: 现在的情况没有太大意义。目前只有连续小波 - 决定是否完全重写或删除它们。离散小波变换超出范围(PyWavelets 对这些做得很好)。
稀疏#
稀疏矩阵格式基本上已经功能齐全,但主要问题是它们表现得像 ``numpy.matrix``(这在 NumPy 的某个时候将被弃用)。
我们想要的是像 numpy.ndarray 一样行为的稀疏数组。在 SciPy 1.8.0 中添加了对一组新类(csr_array 等)的初步支持,并在 1.12.0 中稳定下来,当时为数组添加了构造函数。预计在 1.13.0 中将支持一维数组。
下一步支持稀疏数组:
- 将稀疏数组API扩展到一维数组。
支持COO、CSR和DOK格式。
CSR 1D 支持最小-最大值、索引、算术运算。
帮助其他库从稀疏矩阵转换为稀疏数组。创建转换指南和有用的脚本来标记需要进一步检查的代码。NetworkX、scikit-learn 和 scikit-image 正在进行中或已完成转换为稀疏数组。
在稀疏数组代码成熟后(约一个发布周期?),为稀疏矩阵添加弃用警告。
在
numpy.matrix的弃用/移除上与 NumPy 合作。弃用然后移除稀疏矩阵,转而使用稀疏数组。
- 开始API转换构造函数名称(
diags,``block``等) 注意:整体上,构造函数经历了两次名称变更。一次是从矩阵创建迁移到新的数组创建函数(即
eye->eye_array)。然后第二次变更名称以匹配array_api的名称(即eye_array到eye),在移除稀疏矩阵之后。我们将长期保留*_array版本作为(可能是隐藏的)别名。
- 开始API转换构造函数名称(
添加与
array_api名称匹配的构造函数名称。弃用过渡构造函数名称。
一个替代方案(更具雄心,且尚不清楚是否会实现)正在 pydata/sparse 中进行。为了支持这一努力,我们旨在支持 PyData Sparse 在所有接受稀疏数组的函数中。scipy.sparse.linalg 和 scipy.sparse.csgraph 中对 pydata/sparse 的支持已基本完成。
关于不同的稀疏矩阵格式:有很多种。这些应该保留,但改进/优化应集中在CSR/CSC上,这是首选格式。LIL可能是个例外,它本质上效率不高。如果DOK扩展以支持LIL当前提供的所有操作,则可以删除LIL。
sparse.csgraph#
这个模块状态良好。
稀疏线性代数#
_arpack 和 lobpcg 存在大量未解决的问题。_propack 是 1.8.0 版本中的新功能,其实际稳健性有待确定。
_isolve:
callback 关键字不一致
tol 关键字已损坏,应为相对 tol
Fortran 代码不可重入(但我们不解决,可能从 PyKrilov 重用)
_dsolve:
添加许可证兼容的稀疏Cholesky或不完全Cholesky
添加许可证兼容的稀疏QR
改进 SuiteSparse UMFPACK 的接口
将接口添加到 SuiteSparse CHOLMOD 和 SPQR
空间#
QHull 包装器状态良好,KDTree 也是如此。
spatial.distance 指标的 C++ 重写正在进行中 - 这将提高性能,使行为(例如,对于各种非 float64 输入数据类型)更加一致,并修复一些剩余的数学实现定义问题。
特殊#
尽管仍有许多功能需要提高精度,但可能唯一阻碍进展的是超几何函数、抛物柱面函数和扁球面波函数。处理这一问题的三种可能方法:
获取良好的双精度实现。这对于抛物柱面函数是可行的(正在进行中)。我认为对于超几何函数也是可能的,尽管可能来不及。对于球面波函数,这在当前理论下是不可能的。
移植 Port Boost 的任意精度库,并在底层使用它以获得双精度准确性。这可能是作为超几何函数的一种临时措施;使用任意精度的想法之前已被 @nmayorov 提出,并在 gh-5349 中提到。对于球面波函数可能是必要的,这可以被重用:radelman/scattering。
在文档中添加关于现有实现限制的明确警告。
统计数据#
scipy.stats 子包旨在提供基础的统计方法,这些方法可能涵盖在标准的统计学教材中,如Johnson的“Miller & Freund的概率与工程师的统计学”,Sokal & Rohlf的“生物统计学”,或Zar的“生物统计分析”。它并不寻求复制下游包(如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 所示。
此外,我们应该:
继续努力使
stats和stats.mstats的函数签名更加一致,并添加测试以确保这种情况保持不变。改进统计测试:返回测试统计量的置信区间,并在计算上可行的情况下,实现精确的 p 值计算 - 考虑平局的可能性。