title: 擬合算法
date: 2020-02-21 19:27:07
categories: 數學建模
tags: MATLAB
學習視頻:【強烈推薦】清風:數學建模算法、編程和寫作培訓的視頻課程以及Matlab
老師講得很詳細,很受用!!!
定義
與插值問題不同,在擬合問題中不需要曲線一定經過給定的點。擬合問題的目標是尋求一個函數(曲線),使得該曲線在某種准則下與所有的數據點最為接近,即曲線擬合的最好(最小化損失函數)。
插值和擬合的區別
插值:樣本數n<30
擬合:樣本數n>=30(大樣本)
插值算法中,得到的多項式f(x)要經過所有樣本點。但是如果樣本點太多,那
么這個多項式次數過高,會造成龍格現象。
盡管我們可以選擇分段的方法避免這種現象,但是更多時候我們更傾向於得到
一個確定的曲線,盡管這條曲線不能經過每一個樣本點,但只要保證誤差足夠小即
可,這就是擬合的思想。 (擬合的結果是得到一個確定的曲線)
評價擬合效果

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 R_2 = SSR / SST
%注: mean() 是求均值的函數
強大的曲線擬合工具箱
模擬數據代碼
% (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
模擬數據進行演示
xi是[0,10]上的均勻分布,\(e^{i}\)是標准正態分布的擾動項
clear;clc
x = rand(30,1) * 10; % x是0-10之間均勻分布的隨機向量(30個樣本)
y = 3 * exp(0.5*x) -5 + normrnd(0,1,30,1);
cftool
優秀論文中的cftool運用


cftool的‘騷’操作

作業
題目
根據data2中的中國人口數據,確定你認為最合適 的擬合函數,並說明原因。
模型的建立
擬合算法簡介
擬合指的是已知一系列的點,通過調整某些函數的待定系數使該函數與已知點集的差別最小。如果待定函數是線性,就叫線性擬合,否則稱為作非線性擬合。若表達式也可以是分段函數,這種情況下稱作樣條擬合。
確定擬合函數
第一步:作出人口數量的散點圖,結果如下圖所示:

由圖可知,人口數量曲線有明顯的直線特征,故其函數表達式大致為y=kx+b。
運用最小二乘法

模型的求解
MATLAB 求解最小二乘
利用MATLAB軟件我們求得\(k=702.4485,b=-1.2782×106\),擬合的結果如下圖所示:

利用cftool工具箱
cftool是一款強大的由線擬合工具,且使用起來方便快捷,為了保正擬合結果的准確性,我們利用cftool工具箱選取了一些常見的擬合函數,並進行對比分析,結果如下表所示:

SSE越接近於0,說明誤差越小即擬合的效果越好;對於線性模型,R2越接近於1,說明誤差平方接近於0,擬的效果越好。但同時我們要考慮到函數的形式越簡單越好,綜合以上擬合結果,我們最終認為一次polynomial函數的擬合最為合適。
代碼
%% 導入數據
[~, ~, raw] = xlsread('G:\數學建模學習材料\參考資料\清風數學建模\第1-14講和番外篇的課件和代碼(1月16日修訂版本)\第1-14講和番外篇課件和代碼\第4講.擬合\代碼和例題數據\data2.xlsx','Sheet1','A2:B11');
%% 創建輸出變量
data = reshape([raw{:}],size(raw));
%% 創建表
data2 = table;
%% 將導入的數組分配給列變量名稱
x = data(:,1);
y = data(:,2);
cftool
%% 畫圖與建模
plot(x,y,'o')
xlabel('年份')
ylabel('人口(萬)')
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 % 顯示網格線
f=@(x) k*x+b;
fplot(f,[min(x)-1,max(x)+1])
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
[fitresult, gof] = createFit(x, y)
%% 清除臨時變量
clearvars data raw;
