# 插值和拟合的概念和区别
插值曲线要过数据点,拟合曲线整体效果更好。
插值需要对准了才能插,拟合要求的是最接近的结果、最好的总体效果。
# 一维插值
变量之中存在的函数关系,有时不能确定,而是通过获得的数据来找出两个变量间可能存在的连续。
——《数学建模算法与应用(第2版)》(司守奎主编)
未知 ,但已知 的很多观测点 ,要找一个(可以分段的)函数 ,并且强制要求 经过所有观测点。
公式就略写了,要是用到了,看书就行。
# 分段线性插值
简单的说,就是把每两个节点用直线连接起来。因此其函数表达式也较为显然。
有意思的是,虽然函数计算每点的插值时只用到左右两个点,但这个函数随着点数 的增加,收敛于 ,即 。因此也是用的最多的(如利用三角函数表计算任意三角函数值)。
# 拉格朗日插值
从思想上来说,Lagrange 插值法是通过函数 的已知的 个点 ,构造出一个多项式 来近似 。(这个多项式最高为 次,经过全部 个点)
在 Lagrange 插值中,已知 个点 ,则应用 Lagrange 插值公式得到的 Lagrange 插值多项式 为:
其中
但也是介绍一下概念,并没有太多展开。
# 样条插值
样条 spline
插值的目标就是使函数连续,且在连接处具有连续的曲率。
即,在每一段上 是 m 次多项式,且在整段上, 具有 阶导数,则称 为样条函数。使用样条函数作为结果,就是样条插值。
由于 时,不用考虑其导数,因此分段线性插值也是样条插值(23333
# 三次样条插值
考虑次数为三的样条插值。由上面的定义我们可以设 个区间的表达式为:
共有 个待定系数。
条件对应的方程有:
(1) ; (2) 相邻两段的函数值、一阶导数、二阶导数在临界点相同。
共 个表达式,还需给出两个表达式。由此引出了三个版本的样条插值。
- 。这叫完备三次样条插值函数。
- 若令 ,样条曲线在端点呈水平状态。
- 若以 求三次 Newton 插值多项式(不懂这是什么),以 求三次 Newton 插值多项式,然后令 ,这叫 Lagrange 三次样条插值函数。
- 。这叫自然边界条件。
- ,这叫周期条件。
# MATLAB 插值工具箱
# 一维插值
y = interp1(x0, y0, x, <method>)
其中 <method>
可选:
'nearest'
:最近项插值'linear'
:线性插值(默认)'spline'
:立方样条插值,边界条件为'not-a-knot'
(见下)'cubic'
:立方插值
# 立方样条插值
立方样条插值更推荐使用 csape
:
pp = scape(x0, y0, <conds>, <valconds>); % pp 是 polynomial pieces,多项式分段(函数)
y = fnval(pp, x);
其中 <conds>
为:
- 留空,使用 Lagrange 边界条件
'complete'
:完备立方样条插值,即边界为一阶导数值,值在<valconds>
中给出,若留空则按 Lagrange 边界条件'not-a-knot'
:非扭结条件,即要求前两段表达式的三阶导数相等,且后两段的三阶导数相等,在没有边界条件时常用'periodic'
:周期条件,即'sencond'
:边界为二阶导数值,值在<valconds>
中给出,若留空则取
顺便,还可以将 fnval
改写为匿名函数,然后跑积分:
x0 = [0 3 5 7 9 11 12 13 14 15];
y0 = [0 1.2 1.7 2.0 2.1 2.0 1.8 1.2 1.0 1.6];
x = 0:0.02:15;
pp = csape(x,y);
int1 = integral(@(t)fnval(pp,t), 0,15) % int1 = 22.5788
这和 interp1
后运用积分定义 (其中 取两端点的平均值)求得的结果非常接近。
x0 = [0 3 5 7 9 11 12 13 14 15];
y0 = [0 1.2 1.7 2.0 2.1 2.0 1.8 1.2 1.0 1.6];
x = 0:0.002:15;
method = "spline";
y = interp1(x0, y0, x, method);
int2 = (sum(y)-(y(1) + y(end))/2) * 0.002 % int2 = 22.5788
# 二维插值
二维插值,即节点为二维的插值问题。如测定了若干点的海拔(结点值),然后更精确的绘图。
这里不讲原理,直接讲应用了。
z = interp2(X0, Y0, Z0, X, Y, <method>)
其中 X0
Y0
Z0
为大小相同的网格变量。如果读者不清楚什么是网格变量,或数据不是以网格变量给出的、而是以 x
y
向量形式给出的,请参考 meshgrid
。
<method>
与一维插值相同。
同时,二维的三次样条插值仍然可以使用 csape
,只是输入参数有所变化。如需要,请自行查阅 MATLAB 文档。
如果输入的是散乱的 个节点的 、、 值,可以使用 griddata
进行插值:
Z = griddata(x0, y0, z0, X, Y, <method>)
<method>
与一维插值相同。
# 曲线拟合与最小二乘法
曲线拟合就是给定 个点,寻求一个函数 与给定的点在某种准则下最为接近,即拟合的最好。
线性最小二乘法是最常用的方法,其基本思想为,设
其中 为事先选定的一组线性无关的函数; 为待定系数。
拟合目标(准则)是使得 与 的距离 的平方和最小,称为最小二乘准则,即
可由线性代数知识证明, 一旦确定且线性无关,则 有唯一的解。
现在的问题就在于 的选取。如果通过机理分析(通过对数据和现象的分析对事物内在规律做出的猜想、模型假设)能知道 和 的函数关系,就很容易了。如果不知道,则一般可以通过作图,然后直观地判断应该用什么样的函数。常见的曲线有:
- 直线
- 多项式 (一般 ,不宜太高)
- 单支双曲线
- 指数函数
# 最小二乘法 MATLAB 代码
由于上述的证明 有唯一的解过程略,这里不写运用原理解最小二乘法。如需要,可查阅《数学建模算法及应用(第二版)》。
多项式拟合可使用 polyfit
。也可以直接使用带 GUI 的工具箱函数 cftool
。
a = polyfit(x0, y0, m); % m 为次数,a 为多项式拟合的系数组成的向量
y = polyval(a, x); % 多项式求值
# 最小二乘规划
上面求参数 的过程,可以说是是在求参数值使得目标函数值最小。咦,这不就是最优化问题吗?
所以这里的内容其实回到了规划问题,只是目标函数变成了最小二乘(least square
,lsq
)的形式,即目标函数变为
注意这里的向量 (下同)实际上是参数,对应上面的 中的参数 ;
而这里的 对应的是上面的 。
对于这类规划问题,MATLAB 提供了以下函数,现整合为下表,且一并包含了 polyfit
函数:
函数名 | 适用情况 | 输入参数中的 数据处理 |
---|---|---|
polyfit | 对参数为线性函数 对 为多项式函数 | 无需处理,直接作为函数参数 |
lsqlin | 对参数为线性函数 | 需转化为对应矩阵元素 |
lsqcurvefit | 对参数可为非线性函数 | 无需处理,直接作为函数参数 |
lsnonlin | 对参数可为非线性函数 | 需转化为对应关于参数的函数 |
lsqnonneg | 对参数为线性函数 要求参数非负 | 需转化为对应矩阵元素 |
上表中的“对参数为线性函数”指 对于 为线性函数。一个非线性的例子是:。
顺便一提,由于最小二乘问题能化为二次规划问题,lsqlin
能解决的问题也可以使用 quadprog
解决。
最后,说了这么多,可能还是 cftool
好用(逃
# 曲线拟合与函数逼近
上面的是用曲线去接近一些离散点的数据,下面考虑用一个(简单的)曲线接近一个(复杂的)函数曲线,这便是函数逼近。
与曲线拟合的最小二乘准则对应,函数逼近常用最小平方逼近,即
就是把 改成 ,把求和改成积分。合理。
之后的理论证明和解释因为有点高深,故略过,直接放一个例题的代码,以后需要的时候就照搬叭。
求 在 中的最小平方逼近多项式。
syms x
base=[1,x^2,x^4];
y1=base.'*base
y2=cos(x)*base.'
r1=int(y1,-pi/2,pi/2)
r2=int(y2,-pi/2,pi/2)
a=r1\r2
xishu1=double(a) % 符号数据转化成数值型数据
xishu2=vpa(a,6) % 把符号数据转化成小数型的符号数据
解得 xishu1 = 0.9996 -0.4964 0.0372
,即所求最小平方逼近多项式为
# 例题 黄河小浪底调水调沙问题
由于这部分内容比较简单,在数模中多是作为题目中的一个小点,因此纯插值拟合的题不难。
题目来源:《数学建模算法与应用(第2版)》(司守奎主编)节 5.5
题目重述略。
# 问题分析
问题一要求我们通过给定 24 个时刻的数据,估计任意时刻的数据以及总排沙量,我们采用插值的方式得到任意时刻的数据,再对插值函数进行积分得到总排沙量。
问题二要求我们确定排沙量与水流量的关系,我们对数据进行拟合即可。
# 变量及名词解释
符号 | 含义 |
---|---|
观测时刻,以 6 月 29 日零点开始计时,以秒为单位 | |
观测到 时刻的水流量,单位 | |
观测到 时刻的含沙量,单位 | |
观测到 时刻的排沙量,单位 | |
估计排沙量关于时刻的函数 | |
整个过程的总排沙量 | |
第 次观测的时间点 | |
估计排沙量关于水流量的函数 |
# 模型建立与求解
# 问题一
由于题目的时间是以日期、时分给出的,我们需将其化为以秒为单位的正整数。可得以下关系:
由物理公式可知,排沙量=含沙量*水流量,即:
通过数据处理我们可以得到观测到的每个时刻的排沙量。
对这些数据进行三次样条插值,边界条件为非扭结条件,则可得到任意时刻的估计排沙量 。代入任意时刻即可求得该时刻的估计排沙量。
对 进行积分,就能得到总的排沙量。
编写 MATLAB 代码如下:
hold off;
data = [
1800 1900 2100 2200 2300 2400 2500 2600 2650 2700 2720 2650 2600 2500 2300 2200 2000 1850 1820 1800 1750 1500 1000 900;
32 60 75 85 90 98 100 102 108 112 115 116 118 120 118 105 80 60 50 30 26 20 8 5
];
t = 3600*(8:12:8+23*12);
sand = data(2,:) .* data(1,:);
T = t(1):t(end);
% 插值
pp = csape(t,sand,"not-a-knot");
Sand = fnval(pp,T);
SandTotal = integral(@(t)fnval(pp,t),T(1),T(end));
% 输出排沙量和时间的函数关系图
fplot(@(t)fnval(pp,t),[t(1) t(end)],'b-');
hold on;
plot(t,sand,'r*');
hold off;
pause
% 输出总排沙量和时间的函数关系图
f = @(time) integral(@(t)fnval(pp,t),T(1),time);
fplot(f,[t(1) t(end)])
得到函数图及输出如下:
计算得从第一个检测时刻到最后一个检测时刻,共排沙约 。
# 问题二
问题二要求我们用已知数据拟合出排沙量 和水流量 的函数关系。
考虑到 7.4 8:00 时水流量最大,以该时刻为临界的前后两个时段可能是不同的状态,我们对函数分段进行拟合,前一段为 6.29 8:00 至 7.4 8:00,后一段为 7.4 8:00 至 7.10 20:00。其中中间时刻 7.4 8:00 被计算两次。
由于我们并不清楚其函数关系,所以先以上述数据绘制两幅散点图,然后使用 cftool
进行拟合。
编写 MATLAB 代码如下:
data = [
1800 1900 2100 2200 2300 2400 2500 2600 2650 2700 2720 2650 2600 2500 2300 2200 2000 1850 1820 1800 1750 1500 1000 900;
32 60 75 85 90 98 100 102 108 112 115 116 118 120 118 105 80 60 50 30 26 20 8 5
];
t = 3600*(8:12:8+23*12);
sand = data(2,:) .* data(1,:);
T = t(1):t(end);
w1 = data(1,1:11);
w2 = data(1,11:24);
S1 = sand(1:11);
S2 = sand(11:24);
nexttile;
plot(w1,S1, '*');
title('前半段的散点图');
nexttile;
plot(w2,S2,'*');
title('后半段的散点图');
cftool
我们考虑对左图使用线性函数拟合,右图使用二次曲线拟合,并验证其 值。
对于左图,使用线性拟合的结果为 ,; 对于右图,使用二次曲线拟合的结果为 ,(相比一次下 )。
综上,