鉴于最近遇到非线性函数拟合问题,本人对网上有关matlab多种类型的线性、非线性曲线拟合的方法进行了总结,希望对各位朋友有所帮助。
1. Matlab有一个功能强大的曲线拟合工具箱 cftool ,使用方便,能实现多种类型的线性、非线性曲线拟合。下面简单介绍如何使用这个工具箱。
可以直接在matlab命令行输入cftool命令即可进入cftool窗口。
》cftool
输入命令回车后就得到一下界面
进行曲线拟合的时候,最基本的操作包括点击“data...”按钮和“fitting...”按钮。
1.2 data….按钮
首先,到命令窗口中为点击"data..."做好准备:
》x=[8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20];
》y=[0.6,0.62,0.64, 0.65, 0.66, 0.67, 0.68, 0.68, 0.69, 0.66, 0.65, 0.65,0.64];
》
然后,点击“data...”按钮,选x横坐标和选y纵坐标变量:
1)在弹出的Data窗口中,在X Data选项中选择x,在Y Data中选择y。其中X, Y都是刚刚在命令行所准备的数据变量名。
2)经过此步骤后点击“Createdata set”按钮。这个时候Data对话框背后的对话框中已经有散点图了。然后点击Data中的close按钮.
1.3 fiting ….按钮
在正确设置Data对话框之后,在关闭Data对话框之后,就可以点击fitting...按钮了。会弹出这么一个对话框:
1)在Fitting对话框中点击Newfit后在Fitname为此次曲线取名字:“cftool 曲线拟合”,当有多条曲线需要同时绘制时,每次都需要点击Newfit,然后选择对应的Data set值即对应相应的数据变量就可以绘制多条曲线了。即同时拟合多条曲线。选择data set。
2)选择相应类型的曲线拟合(到其它地方粘贴过来的),点击Type of fit 下拉菜单:
CustomEquations:用户自定义的函数类型
·Exponential:指数逼近,有2种类型, a*exp(b*x) 、 a*exp(b*x) + c*exp(d*x)
·Fourier:傅立叶逼近,有7种类型,基础型是 a0 +a1*cos(x*w) + b1*sin(x*w)
·Gaussian:高斯逼近,有8种类型,基础型是a1*exp(c1-((x-b1)/c1)^2)
·Interpolant:插值逼近,有4种类型,linear、nearest neighbor、cubic spline、shape-preserving
·Polynomial:多形式逼近,有9种类型,linear ~、quadratic ~、cubic ~、4-9thdegree ~
·Power:幂逼近,有2种类型,a*x^b 、a*x^b +c
·Rational:有理数逼近,分子、分母共有的类型是linear ~、quadratic ~、cubic ~、4-5thdegree ~;此外,分子还包括constant型
·Smoothing Spline:平滑逼近(翻译的不大恰当,不好意思)
· Sumof Sin Functions:正弦曲线逼近,有8种类型,基础型是a1*sin(b1*x + c1)
·Weibull:只有一种,a*b*x^(b-1)*exp(-a*x^b)
3)最后再选择一种曲线拟合下的具体类型,点击Apply按钮就可以看见所拟合的曲线了。
如果发现曲线和数据点不是很“磨合”就需要重新选择曲线类型了。
上图是点击了应用按钮之后的状态,在Results中得来的就是拟合数据的曲线函数关系式。
点击Appy后的运行结果为:
1.4 CFTOOL菜单使用
在上面显示的曲线拟合结果中,可以明显的看见横坐标和纵坐标都不是从原点(0,0)开始设置的坐标。那么我们可以使用
Curve Fitting Tool 对话框中Tools菜单中的
Tools中的各个选项的功能:
1)New Cunstom Equation:表示使用自定义的函数来模拟图中显示的散点数据的函数式子。
2)Legend:就是图中显示着“y vs.x cftool 曲线拟合”的那个框。
3)Grid:跟指令grid一样的功能,是曲线背景充满虚线框。
4)Axis Limit Control:设置横轴、纵轴坐标的范围。
2. matlab中直接使用曲线拟合工具:cftool.(不使用cftool的GUI界面)
最基本的使用方法如下,假设我们需要拟合的点集存放在两个向量X和Y中,分别储存着各离散点的横坐标和纵坐标,则在MATLAB中直接键入命令 cftool(X,Y) 就会弹出Curve Fitting Tool的GUI界面,点击界面上的fitting即可开始曲线拟合。
MATLAB提供了各种曲线拟合方法,例如:Exponential, Fourier, Gaussing, Interpolant, Polynomial, Power,Rational, Smoothing Spline, Sum of Functions, Weibull等,当然,也可以使用 Custom Equations.
cftool不仅可以绘制拟合后的曲线、给出拟合参数,还能给出拟合好坏的评价参数(Goodness of fit)如SSE, R-square, RMSE等数据,非常好用。但是如果我们已经确定了拟合的方法,只需要对数据进行计算,那么这种GUI的操作方式就不太适合了,比如在m文件中就不方便直接调用cftool。
MATLAB已经给出了解决办法,可以在cftool中根据情况生成特定的m文件,让我们直接进行特定的曲线拟合并给出参数。具体方法在帮助文件的如下文档中" \ Curve Fitting Toolbox \ Generating M-files From CurveFitting Tool " ,以下简单举例说明
(x1,y1)为一曲线散点
x1=[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0];
y1=[0,5.98e-09,0.00000528,0.0003,0.0041,0.0235,0.071,0.1548,0.2597,0.3724];
cftool(X,Y);
点击Fitting选择一元高斯分布拟合(gaussian),然后就会出现如下拟合图形:
然后在Curve Fitting Tool窗口中点击 " \ File \ Generate M-file " 即可生成能直接曲线拟合的m函数文件,其中使用的拟合方法就是刚才使用的一元高斯分布拟合,文件中这条语句证明了这一点:
ft_ = fittype('gauss1');
保存该m文件(默认叫做createFit.m),调用方法和通常的m文件一样,使用不同的X和Y值就能拟合出不同的曲线。但是,这种调用方法只能看到一个拟合出的图形窗口,拟合参数以及Goodness of fit参数都看不到了,因此需要在刚才的m文件中稍作修改。
找到这句话:
cf_ = fit(X(ok_),Y(ok_),ft_);
修改为:
[cf_,gof] = fit(X(ok_),Y(ok_),ft_);
然后将函数声明 function createFit(X,Y) 修改为 function[cf_,gof] = createFit(X,Y) ,这样我们再调用试试看:
x1=[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0];
y1=[0,5.98e-09,0.00000528,0.0003,0.0041,0.0235,0.071,0.1548,0.2597,0.3724];
[c,g]=createFit(x1,y1);
这样就会弹出拟合图形的窗口,然后再键入c和g,就能查看一元高斯拟合参数及拟合评价参数。
c和g分别是1×1 cfit 数据类型和1×1 struct 数据类型。本例中c包括p1, p2, p3, p4四个成员,即一元高斯拟合的参数;g包括rmse等成员,即拟合评价参数。
3. 线性回归
3.1一元线性回归
3.1.1 命令 polyfit最小二乘多项式拟合
[p,S]=polyfit(x,y,m)
多项式y=a1xm+a2xm-1+…+amx+am+1
其中x=(x1,x2,…,xm)x1…xm为(n*1)的矩阵;
y为(n*1)的矩阵;
p=(a1,a2,…,am+1)是多项式y=a1xm+a2xm-1+…+amx+am+1的系数;
S是一个矩阵,用来估计预测误差.
3.1.2 命令 polyval多项式函数的预测值
Y=polyval(p,x)求polyfit所得的回归多项式在x处的预测值Y;
p是polyfit函数的返回值;
x和polyfit函数的x值相同。
3.1.3 命令 polyconf 残差个案次序图
[Y,DELTA]=polyconf(p,x,S,alpha)求polyfit所得的回归多项式在x处的预测值Y及预测值的显著性为1-alpha的置信区间DELTA;alpha缺省时为0.05。
p是polyfit函数的返回值;
x和polyfit函数的x值相同;
S和polyfit函数的S值相同。
3.1.4命令 polytool(x,y,m)一元多项式回归命令
3.1.5 命令regress多元线性回归(可用于一元线性回归)
b=regress( Y, X )
[b, bint,r,rint,stats]=regress(Y,X,alpha)
b 回归系数
bint 回归系数的区间估计
r 残差
rint 残差置信区间
stats 用于检验回归模型的统计量,有三个数值:相关系数R2、F值、与F对应的概率p,相关系数R2越接近1,说明回归方程越显著;F > F1-α(k,n-k-1)时拒绝H0,F越大,说明回归方程越显著;与F对应的概率p 时拒绝H0,回归模型成立。
Y为n*1的矩阵;
X为(ones(n,1),x1,…,xm)的矩阵;
alpha显著性水平(缺省时为0.05)。
3.2.多元线性回归
3.2.1 命令 regress(见2.5)
3.2.2命令 rstool 多元二项式回归
命令:rstool(x,y,’model’, alpha)
x 为n*m矩阵
y为 n维列向量
model 由下列4个模型中选择1个(用字符串输入,缺省时为线性模型):
linear(线性):
purequadratic(纯二次):
interaction(交叉):
quadratic(完全二次):
alpha 显著性水平(缺省时为0.05)
返回值beta 系数
返回值rmse剩余标准差
返回值residuals残差
4. 非线性拟合
MATLAB 具有多种拟合函数,包括最小二乘法、牛顿法、最速下降法、共轭梯度法、单纯形法等。在此选取8 个(lsqcurvefit、nlinfit、lsqnonlin、fminsearch、fminunc、fgoalattain、curvefit、nlintool)MATLAB 函数进行介绍。
4.1 lsqcurvefit 函数拟合
函数lsqcurvefit 是MATLAB 最优化工具箱里的一个非线性拟合函数,采用最小二乘曲线进行拟合.
格式:lsqcurvefit(f,a,x,y)
f:符号函数句柄,如果是以m文件的形式调用的时候,别忘记加@(用@函数文件名表示,或由inline()函数表示).这里需要注意,f函数的返回值是和y匹对的,即拟合参数的标准是(f-y)^2取最小值,具体看下面的例子
a:最开始预估的值(预拟合的未知参数的估计值)。如下面的问题如果我们预估A为1,B为2,则a=[1 2]
x:我们已经获知的x的值
y:我们已经获知的x对应的y的值
例子1: 一元的情况
问题:对于函数y=a*sin(x)*exp(x)-b/log(x)我们现在已经有多组(x,y)的数据,我们要求最佳的a,b值
%针对上面的问题,我们可以来演示下如何使用这个函数以及看下其效果
>> x=2:10;
>> y=8*sin(x).*exp(x)-12./log(x);
%上面假如是我们事先获得的值
>> a=[1 2];
>> f=@(a,x)a(1)*sin(x).*exp(x)-a(2)./log(x);
%第一种方法使用lsqcurvefit
>> lsqcurvefit(f,a,x,y)
ans =
7.999999999999987 11.999999999988997%和我们预期的值8和12结合得非常好
>>
例子2:多元的情况
问题:我们已知z=a*(exp(y)+1)-sin(x)*b且有多组(x,y,z)的值,现在求最佳系数a,b
>> x=2:10;
>> y=10*sin(x)./log(x);
>> z=4.5*(exp(y)+1)-sin(x)*13.8;
>> f=@(a,x)a(1)*(exp(x(2,:))+1)-sin(x(1,:))*a(2);
>> lsqcurvefit(f,[1 2],[x;y],z)%注意这里面的[x;y],这里的[1 2]表示我们设置f函数里的初始值a(1)=1,,a(2)=2
ans =
4.499999999999999 13.800000000000024
ans =
8.000000000000000 11.999999999999998
>>
%**********************************
%另一种方法,假如我们写了一个如下的m文件
function f=test(a,x)
f=a(1)*sin(x).*exp(x)-a(2)./log(x);
end
%则在上面lsqcurvefit函数调用如下,不要忘记那个@
lsqcurvefit(@test,a,x,y)
4.2 nlinfit(x,y,f,a)
函数nlinfit采用高斯-牛顿法对方程进行非线性最小二乘数据回归
例子1:一元的情况
>> x=2:10;
>> y=8*sin(x).*exp(x)-12./log(x);
%上面假如是我们事先获得的值
>> a=[1 2];
>> f=@(a,x)a(1)*sin(x).*exp(x)-a(2)./log(x);
%第一种方法使用lsqcurvefit
>> nlinfit(x,y,f,a)
ans =
8.000000000000000 11.999999999999998
>>
例子2:多元的情况
问题:我们已知z=a*(exp(y)+1)-sin(x)*b且有多组(x,y,z)的值,现在求最佳系数a,b
>> x=2:10;
>> y=10*sin(x)./log(x);
>> z=4.5*(exp(y)+1)-sin(x)*13.8;
>> f=@(a,x)a(1)*(exp(x(2,:))+1)-sin(x(1,:))*a(2);
>> nlinfit ([x;y],z,f,[1 2])
ans =
4.500000000000000 13.799999999999956
>>
%**********************************
%另一种方法,假如我们写了一个如下的m文件
function f=test(a,x)
f=a(1)*sin(x).*exp(x)-a(2)./log(x);
end
%则在上面nlinfit函数调用如下,不要忘记那个@
nlinfit(x,y,@test ,a)
例子 3:(正态分布函数)问题:对于正态分布函数normcdf(x, μ, σ),我们现在已经有三组(x,y)的数据,我们要求最佳的μ, σ值
>> f = @(b,x) normcdf(x,b(1),b(2));
>> x = [16 18 20]';
>> y = [95.7% 96.5% 96.6%]';
>> p = nlinfit(x,y,f,[0 20]');
注意:这里初始值[0 20]非常重要(预拟合的μ, σ的估计值)),如果选择不当会得到一个无效的结果。
本题的运算结果如下:
p =
-44.914441447503123
35.256506107463366
也就是说该数据符合μ = -44.914441447503123,σ = 35.256506107463366的正态分布。下面验证一下,发现拟合得很不错:
>> normcdf(x,p(1),p(2))
ans =
0.957983505571815
0.962826945152314
0.967204209704196
例子 4:(对数正态分布函数)问题:对于对数正态分布函数logncdf(x, μ, σ),我们现在已经有三组(x,y)的数据,我们要求最佳的μ, σ值
主函数:
clc
clear all
x = [0.12 0.47 0.82]';
y = [36.8 90 98]'/100;
Inipa=[-1.83 0.83]';
[mu sigma]=fit_logncdf(x,y,Inipa)
子函数:
function [mu sigma]=fit_logncdf(x,y,Inipa)
fun= @(b,x) logncdf(x,b(1),b(2));%%用@函数文件名表示, 或由inline()函数表示
p = nlinfit(x,y,fun,Inipa);
plot(x,y,'b*')
x=0:0.1:2;
f=logncdf(x,p(1),p(2));
hold on
plot(x,f,'ro')
mu=p(1);
sigma=p(2);
注意:这里初始值[-1.83 0.83]非常重要(预拟合的μ, σ的估计值)),如果选择不当会得到一个无效的结果。
4.3 lsqnonlin函数拟合
函数lsqnonlin 也是运用最小二乘法进行拟合,步骤如下:
首先,建立f.m 文件:
function val=f(p,xdata,ydata)
err=p(1)+(p(2)-p(1))./(1+(p(3).*xdata).^p(4)).^(1.-1./p(4))-ydata;
% xdata,ydata 为输入初始数据;p( )为曲线参数
val=err*err';
% val 为方差
之后,输入初始数据,再代入lsqnonlin 拟合函数拟合:
% 创建优化选项结构
options=optimset( 'largescale','off');
Parameters=lsqnonlin(@f,a,[],[],options,xdata,ydata)
4.4 fminsearch /fminunc函数拟合
函数fminsearch 是用单纯形法寻优,步骤如下。
首先,建立f.m 文件:
function val= f(p,xdata,ydata) %定义val 函数
global xdata ydata %定义全局变量
err=p(1)+(p(2)-p(1))./(1+(p(3).*xdata).^p(4)).^(1.-1./p(4))-ydata;
% xdata,ydata 为输入初始数据;p( )为曲线参数,在Command Window 输入初始数据:
%设定迭代初始值a,
输入初始数据后,代入fminsearch 拟合函数拟合:
Parameters =fminsearch(@f,a)
Parameters =fminunc(@f,a)
4.5 fminunc 函数拟合
函数fminunc 也是非线性规划函数的一种,步骤如下。
首先,建立f.m 文件,再代入fminunc 拟合函数拟合:
Parameters= fminunc ('f',a)
4.6 fgoalattain 函数拟合
函数fgoalattain 属于多目标规划函数,应用过程如下。
首先,建立f.m 文件,再代入fgoalattain 拟合函数拟合:
Parameters = fgoalattain ('fun', a,0, 0)
4.7 curvefit 函数拟合
函数curvefit 是数学建模工具箱中的一个非线性函数拟合工具,应用过程如下。
首先,建立f.m 文件并输入初始数据,再代入
curvefit 拟合函数拟合,内容如下:
Parameters = curvefit ( 'f', a, xdata,ydata)
4.8 nlintool 函数拟合
函数nlintool 是进行数据非线性方程回归的用户交互图形显示函数,应用过程如下。
首先,建立f.m 文件并输入初始数据,再代入curvefit 拟合函数拟合:
nlintool ( xdata , ydata , 'f' , a )
此时, 出现非线性方程回归交互图, 点击 “Export…”按钮,将生成曲线拟合参数。如要显示拟合参数,可直接输入命令:
%显示拟合参数
beta
* 4.1~4.8 中均需要预拟合的未知参数的估计值,属于局部优化。
4.9 用遗传算法拟合 (全局优化)
鉴于预拟合的未知参数的估计值选择不当会得到一个无效的结果。选择用遗传算法进行全局优化的结果作为预拟合的未知参数的估计值,然后再用4.1~4.8进行局部优化。以上面4.2中的例子4为例:
主函数:
clc
clear all
x = [0.12 0.47 0.82]';
y = [36.8 90 98]'/100;
Inipa=[-1.83 0.83]';
[mu sigma]=fit_logncdf(x,y,Inipa)
子函数:
function [mu sigma]=fit_logncdf(xc,yc)
fun= @(b,x) logncdf(x,b(1),b(2));%%用@函数文件名表示, 或由inline()函数表示
ee=@(x)(yc(1)-logncdf(xc(1),x(1),x(2)))^2+(yc(2)-logncdf(xc(2),x(1),x(2)))^2+(yc(3)-logncdf(xc(3),x(1),x(2)))^2;
[inipa]=ga(ee,2,[],[],[],[],[-50,-2],[2,50]);
Inipa=inipa';
%%%%Inipa=[-1.83 0.83]';
p = nlinfit(xc,yc,fun,Inipa);
plot(xc,yc,'b*')
xcc=0:0.1:2;
f=logncdf(xcc,p(1),p(2));
hold on
plot(xcc,f,'ro')
mu=p(1);
sigma=p(2);
4.10globalsearch
>> x=2:10;
>> y=10*sin(x)./log(x);
>> f=@(a,x)a(1)*(exp(x(2,:))+1)-sin(x(1,:))*a(2);
>> opts = optimset('Algorithm','interior-point');>> problem=createOptimProblem('fmincon','objective',f,'x0',[2;5]'lb' ,[12;20],'ub',5,'options',opts);>> gs = GlobalSearch;>> [x,f] = run(gs,problem)
4.11 multistart
>> k1=13;k2=1.3;k3=9.1
>> xdata=0:pi/100:pi;
>> ydata=k1*exp(k2*xdata)+k3*sin(xdata);
>> f=@(x)norm(x(1).*exp(x(2).*xdata+x(3).*sin(xdata)-ydata);
>> ms=Multistart;
>> opts=optimset(‘algorithm’,’interior-point’,’largescale’,’off’);
>> problem=creatoptomproblem(‘fmincon’,’x0’,[10,1,8],’objective’,f,’lb’,[1,0,1],’ub’,[20,10,15],’options’,opts);
>> [xminm,fminm,flagm,outptm,manyminsm]=run(ms,problem,200)
由于作者学识及精力有限,错误之处在所难免,敬请批评指正。
张士博
2014.04.22于大连大连理工大学建设工程学部
抗震研究所综合试验4号楼208室