数学插值与三次样条曲线
本文介绍了样条曲线的原理,以及如何计算三次样条曲线。
一、从插值问题说起
样条函数是一种用于多项式插值的分段函数。
先来解释一下什么是多项式插值。在科学实践中,我们经常会遇到这种情况:采集到了多个样本点,然后对这些样本点进行处理,用一个函数代表这些样本点的特征。一般我们有两种策略去提取这些样本点的特征:(1)拟合(2)插值。拟合不要求方程通过所有的已知点,讲究神似,就是整体趋势一致。插值则是形似,每个已知点都必会穿过,但是高阶会出现龙格现象(Runge Phenomenon) ,所以一般采用分段插值。而样条曲线,特别是分段三次样条曲线,就是一种很常用的插值方法。
龙格现象(Runge Phenomenon) :对于某些函数,使用均匀节点构造高次多项式差值时,在插值区间的边缘的误差可能很大的现象。如下图所示,蓝线为样本点的真实方程( $y=1/(1-25\times x^2)$ ,红线为高阶函数插值结果,可以看出其与实际方程差别很大 )
高阶函数插值会出现上述问题,那么另一种方法就是分段函数插值了。最简单的分段函数就是直接用线段连接各个点,但那样得到的曲线并不平滑,各段函数之间有很大的转折。另一种策略就是用曲线进行插值,这就是所谓的样条曲线。
样条曲线(spline)这个词来源于一种在工程制图时用来画出光滑形状的工具,这种工具一般为富有弹性的细木条或薄钢条。由这样的样条形成的曲线在连接点处具有连续的坡度与曲率。
二、三次样条(cubic spline)曲线
如前文所述,要想平滑插值,我们可以在每一段区间使用曲线。例如,我们可以在各段曲线的交界处令插值方程 $S(x)$ 连续,插值方程的一次导函数 $S’(x)$ 连续,二次导 $S’’(x)$ 也连续,从而获得平滑的插值曲线。由此,在每个小区间上,插值函数都是一个三次方程,这就是三次样条曲线函数的由来。
三次样条函数的计算方法如下:
给定区间 $[x_0,x_n]$ 以及属于这一区间的 $n-1$ 个样本点 $x_1,x_2,…,x_{n-1}$ ,我们可以以这些样本点为界将整个区间分为 $n$ 个小段 $[(x_0,x_1),(x_1,x_2),…,(x_{n-1},x_n)]$ 。在这些小段上,三次样条函数满足以下条件:
- 对于 $\forall i \in [0,n)$ ,在区间 $[x_i,x_{i+1}]$ 上, $S(x)=S_i(x)$ 都是一个三次方程
- 满足插值条件 $S(x_i)=y_i\ (i=0,1,…,n)$
- 曲线光滑,即 $S(x),S’(x),S’’(x)$ 连续
则这个三次方程 $S_i(x)$ 可以构造为以下形式:
$$
y=a_i+b_ix+c_ix^2+d_ix^3
$$
在每个小区间 $[x_i,x_{i+1}]$ 上,要求的未知数个数有四个( $a_i,b_i,c_i,d_i$ )。有 $n$ 个小区间,因此未知数总数为 $4n$ 。我们需要 $4n$ 个方程求解这些未知数。
幸运的是,根据三次样条函数需要满足的条件,我们可以得到 $4n-2$个方程,其中插值方程 $S(x)$ 连续这一条件可以构造出 $2n$ 个方程,插值方程的一次导函数 $S’(x)$ 连续和二次导函数 $S’’(x)$ 连续各可以构造出 $n-1$ 个方程。还缺少两个方程就可以解出所有未知数,这两个方程由边界条件获得。
对于三次样条函数来说,边界条件有三种:
自然边界 ( Natural Spline ):指定端点二阶导数为0, $S’’(x_0)=S’’(x_n)=0$
固定边界 ( Clamped Spline ): 指定端点一阶导数的值为固定值。
非扭结边界( Not-A-Knot Spline ): 强制第一个插值点的三阶导数值等于第二个点的三阶导数值,最后第一个点的三阶导数值等于倒数第二个点的三阶导数值。
三种边界条件的区别如下图所示。可以看出,自然边界和非扭结边界看起来更自然一点。
如此,我们得到了 $4n$ 个方程组,可以解对应的 $4n$ 个方程系数。具体推导略,主要涉及多元一次函数的解法,或者参考文章:《三次样条(cubic spline)插值》。总之在确定方程以后,主要工作就是解方程组。
三、代码方法求解三次样条曲线
scipy
库是一个强大的科学计算函数库,其中提供了interpolate
模块,实现了多种插值方法。其中,scipy.interpolate.CubicSpline
是三次样条插值的官方实现。我们可以使用这一模块来实现插值程序。
下面的程序将接收两个数组作为输入,一个代表样本点的x坐标,另一个代表y坐标,返回一个代表样条曲线系数的矩阵。
1 | import numpy as np |
样条函数的系数矩阵:
1 | [[ 0.28888889 0.28888889 0.55555556 -0.51111111 -0.51111111] |
四、其他样条曲线
上述方法为三次样条曲线的原理和计算方法。但样条曲线的家族成员还有很多,例如smooth P-spline、bivariate P-spline等。这些样条曲线的计算原理大同小异,并且在不同的领域有重要作用,例如三次样条插值主要用于生成平滑曲线,而平滑P样条和二元P样条更多用于统计建模和分析。
- B-spline(基础样条函数):B-spline是样条函数中最基础且最常用的一种,它是通过一组控制点来定义的,并且具有局部支撑性,即改变一个控制点只会影响到该点附近的曲线形状。B-spline曲线在每个区间内部是多项式函数,通常是三次多项式。本文前述的三次样条曲线即属于这一类函数。
- P-spline(惩罚样条函数):P-spline是”Penalized Spline”的简称,它是一种通过添加惩罚项来增强样条函数光滑性的方法。在P-spline中,我们不仅要求样条函数通过所有的数据点,而且要求样条函数的曲率(二阶导数)尽可能小,以此来增加曲线的光滑性。这个要求是通过在目标函数中添加一个惩罚项来实现的。它的优点是可以自动选择平滑参数,而且计算速度较快。它的缺点是可能对数据的噪声敏感,而且不能很好地处理不规则的网格数据
- S-spline(光滑样条函数):S-spline是”Smoothing Spline”的简称。与P-spline类似,S-spline也是通过最小化一个包含惩罚项的目标函数来求解样条函数的。不过,S-spline通常用于非参数回归中,它的目标是找到一个函数,该函数在拟合数据的同时,也使得函数本身的粗糙度(即曲线的弯曲程度)最小。
总的来说,这三种样条函数的主要区别在于如何权衡拟合精度和光滑性。B-spline是最基础的样条函数,它不包含任何惩罚项,因此它的形状完全取决于控制点。P-spline和S-spline则通过添加惩罚项来增加 光滑性,但它们的目标函数和求解方法略有不同。
参考:
- 龙格现象(Runge Phenomenon) - sslchi的文章 - 知乎 https://zhuanlan.zhihu.com/p/138747068
- 三次样条(cubic spline)插值 - 阿贵的文章 - 知乎 https://zhuanlan.zhihu.com/p/62860859
- 样条函数 - 百度百科 https://baike.baidu.com/item/%E6%A0%B7%E6%9D%A1%E5%87%BD%E6%95%B0/5863303
- 从零开始几何处理:函数拟合 - 启思的文章 - 知乎 https://zhuanlan.zhihu.com/p/412459069
拓展阅读:- R smooth.spline 拟合平滑样条曲线 https://vimsky.com/examples/usage/r-stats-smooth.spline-eh.html
- B样条算法(B-spline) - 矢月的文章 - 知乎 https://zhuanlan.zhihu.com/p/260724041
- 从零开始几何处理:RBF函数 - 启思的文章 - 知乎 https://zhuanlan.zhihu.com/p/413596878