scipy.interpolate.

make_smoothing_spline#

scipy.interpolate.make_smoothing_spline(x, y, w=None, lam=None, *, axis=0)[source]#

创建满足广义交叉验证(GCV)准则的平滑B样条。

使用 lam 计算平滑三次样条函数(的系数),以控制曲线平滑程度与数据接近程度之间的权衡。如果 lam 为 None,则使用 GCV 准则 [1] 找到它。

平滑样条是正则化加权线性回归问题的解:

\[\sum\limits_{i=1}^n w_i\lvert y_i - f(x_i) \rvert^2 + \lambda\int\limits_{x_1}^{x_n} (f^{(2)}(u))^2 d u\]

其中 \(f\) 是样条函数,\(w\) 是权重向量,\(\lambda\) 是正则化参数。

如果 lam 为 None,我们使用 GCV 准则找到最优正则化参数;否则,我们使用给定参数解决正则化加权线性回归问题。该参数以以下方式控制权衡:参数越大,函数越平滑。

参数:
xarray_like, shape (n,)

横坐标。n 必须至少为 5。

yarray_like, shape (n, …)

纵坐标。n 必须至少为 5。

warray_like, shape (n,), optional

权重向量。默认为 np.ones_like(x)

lamfloat, (\(\lambda \geq 0\)), optional

正则化参数。如果 lam 为 None,则通过 GCV 准则找到。默认为 None。

axisint, optional

数据轴。默认为零。假设 y.shape[axis] == n,并且 y 的所有其他轴都是批处理轴。

返回:
funcBSpline 对象

一个对象,表示一个基于 B 样条的样条曲线,其解是平滑样条问题通过 GCV 准则 [1](如果 lam 为 None)或使用给定参数 lam 得到的。

说明

该算法是对 Woltring 在 FORTRAN [2] 中引入的算法进行的洁净室(clean room)重新实现。由于许可问题,原版不能在 SciPy 源代码中使用。重新实现的细节在此处讨论(仅俄语)[4]。

如果权重向量 w 为 None,我们假设所有点在权重方面都是相等的,并且权重向量是全一向量。

请注意,在加权残差平方和中,权重没有平方:\(\sum\limits_{i=1}^n w_i\lvert y_i - f(x_i) \rvert^2\),而在 splrep 中,求和是基于平方权重构建的。

在初始问题病态的情况下(例如,\(X^T W X\) 乘积,其中 \(X\) 是设计矩阵,不是正定矩阵),会引发 ValueError。

参考文献

[1]

G. Wahba,“估计平滑参数”,载于 Spline models for observational data,费城,宾夕法尼亚州:工业与应用数学学会,1990年,第 45-65 页。DOI:10.1137/1.9781611970128

[2]

H. J. Woltring,一个用于广义交叉验证样条平滑和微分的 Fortran 包,Advances in Engineering Software, vol. 8, no. 2, pp. 104-113, 1986。DOI:10.1016/0141-1195(86)90098-7

[3]

T. Hastie, J. Friedman, and R. Tisbshirani,“平滑样条”,载于 The elements of Statistical Learning: Data Mining, Inference, and prediction,纽约:施普林格,2017年,第 241-249 页。DOI:10.1007/978-0-387-84858-7

[4]

E. Zemlyanoy,“广义交叉验证平滑样条”,学士论文,2022年。https://www.hse.ru/ba/am/students/diplomas/620910604 (俄语)

示例

生成一些带噪声的数据

>>> import numpy as np
>>> np.random.seed(1234)
>>> n = 200
>>> def func(x):
...    return x**3 + x**2 * np.sin(4 * x)
>>> x = np.sort(np.random.random_sample(n) * 4 - 2)
>>> y = func(x) + np.random.normal(scale=1.5, size=n)

生成平滑样条函数

>>> from scipy.interpolate import make_smoothing_spline
>>> spl = make_smoothing_spline(x, y)

绘制两者

>>> import matplotlib.pyplot as plt
>>> grid = np.linspace(x[0], x[-1], 400)
>>> plt.plot(x, y, '.')
>>> plt.plot(grid, spl(grid), label='Spline')
>>> plt.plot(grid, func(grid), label='Original function')
>>> plt.legend(loc='best')
>>> plt.show()
../../_images/scipy-interpolate-make_smoothing_spline-1.png