插值与拟合

插值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
% 分段三次埃尔米特插值
x = -pi:pi; y = sin(x);
new_x = -pi:0.1:pi;
p = pchip(x,y,new_x);
figure(1); % 在同一个脚本文件里面,要想画多个图,需要给每个图编号,否则只会显示最后一个图哦~
plot(x, y, 'o', new_x, p, 'r-')

% plot函数用法:
% plot(x1,y1,x2,y2)
% 线方式: - 实线 :点线 -. 虚点线 - - 波折线
% 点方式: . 圆点 +加号 * 星号 x x形 o 小圆
% 颜色: y黄; r红; g绿; b蓝; w白; k黑; m紫; c青


% 三次样条插值和分段三次埃尔米特插值的对比
x = -pi:pi;
y = sin(x);
new_x = -pi:0.1:pi;
p1 = pchip(x,y,new_x); %分段三次埃尔米特插值
p2 = spline(x,y,new_x); %三次样条插值
figure(2);
plot(x,y,'o',new_x,p1,'r-',new_x,p2,'b-')
legend('样本点','三次埃尔米特插值','三次样条插值','Location','SouthEast') %标注显示在东南方向
% 说明:
% LEGEND(string1,string2,string3, …)
% 分别将字符串1、字符串2、字符串3……标注到图中,每个字符串对应的图标为画图时的图标。
% ‘Location’用来指定标注显示的位置


% n维数据的插值
x = -pi:pi; y = sin(x);
new_x = -pi:0.1:pi;
p = interpn (x, y, new_x, 'spline');
% 等价于 p = spline(x, y, new_x);
figure(3);
plot(x, y, 'o', new_x, p, 'r-')

% 人口预测(注意:一般我们很少使用插值算法来预测数据,随着课程的深入,后面的章节会有更适合预测的算法供大家选择,例如灰色预测、拟合预测等)
population=[133126,133770,134413,135069,135738,136427,137122,137866,138639, 139538];
year = 2009:2018;
p1 = pchip(year, population, 2019:2021) %分段三次埃尔米特插值预测
p2 = spline(year, population, 2019:2021) %三次样条插值预测
figure(4);
plot(year, population,'o',2019:2021,p1,'r*-',2019:2021,p2,'bx-')
legend('样本点','三次埃尔米特插值预测','三次样条插值预测','Location','SouthEast')

拟合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
clear;clc
load data1
plot(x,y,'o')
% 给x和y轴加上标签
xlabel('x的值')
ylabel('y的值')
n = size(x,1);
k = (n*sum(x.*y)-sum(x)*sum(y))/(n*sum(x.*x)-sum(x)*sum(x))
b = (sum(x.*x)*sum(y)-sum(x)*sum(x.*y))/(n*sum(x.*x)-sum(x)*sum(x))
hold on % 继续在之前的图形上来画图形
grid on % 显示网格线

% % 画出y=kx+b的函数图像 plot(x,y)
% % 传统的画法:模拟生成x和y的序列,比如要画出[0,5]上的图形
% xx = 2.5: 0.1 :7 % 间隔设置的越小画出来的图形越准确
% yy = k * xx + b % k和b都是已知值
% plot(xx,yy,'-')

% 匿名函数的基本用法。
% handle = @(arglist) anonymous_function
% 其中handle为调用匿名函数时使用的名字。
% arglist为匿名函数的输入参数,可以是一个,也可以是多个,用逗号分隔。
% anonymous_function为匿名函数的表达式。
% 举个小例子
% z=@(x,y) x^2+y^2;
% z(1,2)
% % ans = 5
% fplot函数可用于画出匿名一元函数的图形。
% fplot(f,xinterval) 将匿名函数f在指定区间xinterval绘图。xinterval = [xmin xmax] 表示定义域的范围

f=@(x) k*x+b;
fplot(f,[2.5,7]);
legend('样本数据','拟合函数','location','SouthEast')

y_hat = k*x+b; % y的拟合值
SSR = sum((y_hat-mean(y)).^2) % 回归平方和
SSE = sum((y_hat-y).^2) % 误差平方和
SST = sum((y-mean(y)).^2) % 总体平方和
SST-SSE-SSR % 5.6843e-14 = 5.6843*10^-14 matlab浮点数计算的一个误差
R_2 = SSR / SST

前置知识

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
% (1)randi : 产生均匀分布的随机整数(i = int)  
%产生一个1至10之间的随机整数矩阵,大小为2x5;
s1 = randi(10,2,5)
%产生一个-5至5之间的随机整数矩阵,大小为1x10;
s2 = randi([-5,5],1,10)

% (2) rand: 产生0至1之间均匀分布的随机数
%产生一个0至1之间的随机矩阵,大小为1x5;
s3 = rand(1,5)
%产生一个a至b之间的随机矩阵,大小为1x5; % a + (b-a) * rand(1,5); 如:a,b = 2,5
s4= 2 + (5-2) * rand(1,5)

% (3)normrnd:产生正态分布的随机数
%产生一个均值为0,标准差(方差开根号)为2的正态分布的随机矩阵,大小为3x4;
s5 = normrnd(0,2,3,4)

% (4)roundn—任意位置四舍五入
% 0个位 1十位 2百位 -1小数点后一位
a = 3.1415
roundn(a,-2) % ans = 3.1400
roundn(a,2) % ans = 0
a =31415
roundn(a,2) % ans = 31400
roundn(5.5,0) %6
roundn(5.5,1) %10
1
2
3
4
5
clear;clc 
x = rand(30,1) * 10; % x是0-10之间均匀分布的随机向量(30个样本)
y = 3 * exp(0.5*x) -5 + normrnd(0,1,30,1);
% cftool

CSDN博客搬运

一维插值

1
2
3
hours = 1:12;
temps = [5,7,9,16,24,28,31,29,22,25,27,24];
t = interp1(hours,temps,[3.5,6.3,7.2],'linear')

interp1是 MATLAB 中用于一维插值的函数。它可以用于在给定数据点上进行线性或其他类型的插值。在例子中,已经定义了时间点hours和对应的温度数据点temps,然后使用interp1来插值在一些新的时间点上的温度值。

code

1
hours = 1:12; % 时间点 temps = [5,7,9,16,24,28,31,29,22,25,27,24]; % 对应的温度数据点 % 在新的时间点上进行线性插值 new_hours = [3.5, 6.3, 7.2]; % 新的时间点 interpolated_temps = interp1(hours, temps, new_hours, 'linear'); disp(interpolated_temps); 

在这个例子中,interp1的语法是:

code

1
Vq = interp1(X, V, Xq, method); 

其中:

  • X是原始数据点的横坐标(这里是hours)。
  • V是原始数据点的纵坐标(这里是temps)。
  • Xq是要在其上进行插值的新横坐标(这里是new_hours)。
  • method是插值方法,这里使用线性插值,可以选择其他方法,如'spline'等。

在这个例子中,interpolated_temps是在新时间点上通过线性插值得到的温度值。

运行结果

1
2
3
>> test1
t =
12.5000 28.9000 30.6000

三次样条插值

1
2
3
4
5
6
7
8
years = 1900:10:2010;   % 年份数据点
production = [75.995,91.972,105.711,123.203,131.699,150.697,179.323,203.212,226.505,249.633,256.344,267.893]; % 对应的产量数据点

% 在 1995 年进行三次样条插值
p1995 = interp1(years, production, 1995, 'pchip');

% 由于版本问题,这里的三次样条命令为'phip'
plot(years, production, '-*');

在 MATLAB 中,pchip是三次样条插值方法(Piecewise Cubic Hermite Interpolating Polynomial)的一种。三次样条插值是一种用于在给定数据点之间进行平滑插值的技术。pchip 插值使用分段三次 Hermite 曲线,确保插值曲线在原始数据点上是光滑的。

在例子中,使用了interp1函数来进行三次样条插值,代码如下:

code

1
years = 1900:10:2010; % 年份数据点 production = [75.995,91.972,105.711,123.203,131.699,150.697,179.323,203.212,226.505,249.633,256.344,267.893]; % 对应的产量数据点 % 在 1995 年进行三次样条插值 p1995 = interp1(years, production, 1995, 'pchip'); % 由于版本问题,这里的三次样条命令为'phip' plot(years, production, '-*'); 

这里的'pchip'表示使用三次样条插值方法,确保在插值曲线上保持平滑。interp1函数将在给定的年份数据点上插值得到 1995 年的产量值,并将结果存储在变量p1995中。在plot命令中,你可以看到原始数据点的图形以及插值曲线。

运行结果

1
2
>> test2
p1995 = 253.2278

二维插值

1
2
3
4
x = 1:5;
y = 1:3;
temps=[82,81,80,82,84;79,63,61,65,81;84,84,82,85,86];
mesh(x,y,temps)
1
2
3
4
5
6
7
x = 1:5;
y = 1:3;
temps = [82,81,80,82,84;79,63,61,65,81;84,84,82,85,86];
xi = 1:0.2:5;
yi = 1:0.2:3;
zi = interp2(x,y,temps,xi',yi,'cubic');
mesh(xi,yi,zi)
1
2
3
4
5
6
x = [0.5,1.0,1.5,2.0,2.5,3.0];
y = [1.75,2.45,3.81,4.80,7.00,8.60];
p = polyfit(x,y,2)
x1 = 0.5:0.05:3.0;
y1 = polyval(p,x1);
plot(x,y,'-*r',x1,y1,'-b')

这段 MATLAB 代码用于进行多项式拟合和绘制拟合曲线。下面是对每一句的解释:

  1. x = [0.5,1.0,1.5,2.0,2.5,3.0]; 定义了横坐标的数据点。
  2. y = [1.75,2.45,3.81,4.80,7.00,8.60]; 定义了纵坐标的数据点。
  3. p = polyfit(x, y, 2); 使用 polyfit 函数进行二次多项式拟合。这将返回一个包含多项式系数的向量 p,使得 polyval(p, x) 可以计算拟合曲线在给定 x 值上的纵坐标值。
  4. x1 = 0.5:0.05:3.0; 定义了一系列更密集的横坐标值,用于在拟合曲线上绘制平滑的曲线。
  5. y1 = polyval(p, x1); 使用 polyval 函数计算拟合曲线在新的横坐标值 x1 上的纵坐标值。
  6. plot(x, y, '-*r', x1, y1, '-b') 使用 plot 函数绘制图形。'-*r'表示绘制原始数据点,使用红色星号标记;'-b'表示绘制拟合曲线,使用蓝色实线。

综合起来,这段代码进行了二次多项式拟合,并将原始数据点和拟合曲线绘制在同一张图上,以便进行可视化比较。

在 MATLAB 中,polyfit函数用于进行多项式拟合。其中的参数2表示拟合的多项式的次数。具体来说,polyfit(x, y, 2)表示对给定的数据点xy进行二次多项式拟合。

数据预处理

数据不一致性,如单位。

噪声数据,错误的数据,异常的数据,偏离期望值或常理。

img
img