实用计算方法实验二——多项式最小二乘法拟合
实用计算方法实验二——多项式最小二乘法拟合
采用mlx,即matlab的实时脚本,便于观察结果和发布过程。
- 二次多项式
- 三次多项式
- 指数函数
- 评价拟合效果
- 附录:Doolittle函数解矛盾方程组
- 二次多项式
%二次多项式 最小二乘法 解矛盾方程组 拟合
%形如a0*1+a1*x+a2*x^2的拟合
clear
clc
x=[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15];
y=[352 211 197 160 142 106 104 60 56 38 36 32 21 19 15];
m=size(x,2); %获得数据点个数
%n=input('请输入phi(x)的个数:');
n=3;%n即为phi(x)的个数
syms symsx
f = symfun([1,symsx,symsx^2],symsx);%在这里可以修改phi(x)的表达式的形式与个数,如symsx^2,在建立法方程时的值为x^2,cos(symsx)则建立法方程时为cos(x)
expr = formula(f);
表达式分别为
expr(1)
expr(2)
expr(3)
构建的法方程的A与Y
A=zeros(m,n); %构造法方程所需的A和Y
for j=1:n
temp =subs(expr(j),symsx,x);
temp2 = double(temp);
for i=1:m
A(i,j)=temp2(i);
end
end
A
Y=zeros(m,1);
for k=1:m
Y(k,1)=y(k);
end
%a=(A'*A)\(A'*Y);%左除注意
%左除即可解出a了,这里使用一下Doolittle分解法
Doolittle分解法解矛盾方程组
a=Doolittle(A'*A,A'*Y)
%误差的平方和
a1=zeros(n,1);
for i=1:n
a1(i,1)=a(i);
end
c=(A*a1-Y);
Q=0;
for i=1:m
Q=Q+c(i)^2;
end
误差的平方和Q为
Q;
Q1=Q
fprintf( 'a0: %f \t a1: %f a2: %f\n' , a(1), a(2), a(3)) ;
得到的二次函数关系
fprintf( '%f+(%f)*x+(%f)*x^2 \n' , a(1), a(2), a(3)) ;
for k=1:m
yi(k)=a(1)+a(2)*x(k)+a(3)*x(k)^2;
end
绘制散点图
plot(x,y,'o',x,yi,'*');
legend('真值','二次多项式')
hold on;
- 三次多项式
%三次多项式 最小二乘法 解矛盾方程组 拟合
%形如a0*1+a1*x+a2*x^2+a3*x^3的拟合
x=[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15];
y=[352 211 197 160 142 106 104 60 56 38 36 32 21 19 15];
m=size(x,2); %获得数据点个数
n=4;%n即为phi(x)的个数
syms symsx
f = symfun([1,symsx,symsx^2,symsx^3],symsx);%在这里可以修改phi(x)的表达式的形式与个数,如symsx^2,在建立法方程时的值为x^2,cos(symsx)则建立法方程时为cos(x)
expr = formula(f);
表达式分别为
expr(1)
expr(2)
expr(3)
expr(4)
构建法方程的A与Y
A=zeros(m,n); %构造法方程所需的A和Y
for j=1:n
temp =subs(expr(j),symsx,x);
temp2 = double(temp);
for i=1:m
A(i,j)=temp2(i);
end
end
A
Y=zeros(m,1);
for k=1:m
Y(k,1)=y(k);
end
Doolittle分解法解矛盾方程组
%a=(A'*A)\(A'*Y);
a=Doolittle(A'*A,A'*Y);
a
%误差的平方和
a1=zeros(n,1);
for i=1:n
a1(i,1)=a(i);
end
c=(A*a1-Y);
Q=0;
for i=1:m
Q=Q+c(i)^2;
end
误差的平方和Q为
Q;
Q2=Q
fprintf( 'a0: %f \t a1: %f \t a2: %f \t a3: %f \n' , a(1), a(2), a(3) ,a(4)) ;
得到的三次函数关系
fprintf( '%f+(%f)*x+(%f)*x^2+(%f)*x^3 \n' , a(1), a(2), a(3), a(4)) ;
for k=1:m
yi2(k)=a(1)+a(2)*x(k)+a(3)*x(k)^2+a(4)*x(k)^3;
end
绘制散点图
plot( x,yi2,'p');
legend('真值','二次多项式','三次多项式')
- 建立拟合效果评价标准
即误差平方和的大小Q,二次函数误差平方和为Q1,三次函数误差平方和为Q2,Q值越小,拟合效果越好
Q1=5948.69534583064
Q2=4138.86062989298
Q1
Q2
%尝试采用y=a*exp(b*x)形式的函数拟合
令
x=[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15];
n=size(x,2);
xsum=sum(x);
xva=xsum/n
y=[352 211 197 160 142 106 104 60 56 38 36 32 21 19 15];
u=log(y)
usum=sum(u);
uva=usum/n
mulxu=xsum*usum
xsum2=xsum^2
xu=x.*u;
xusum=sum(xu);
x2=x.*x;
x2sum=sum(x2);
b=(n*xusum-mulxu)/(n*x2sum-xsum2)
a1=uva-b*xva
%scatter(x,u,x,b*x+a1)
a=exp(a1)
得到
x=[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15];
y=[352 211 197 160 142 106 104 60 56 38 36 32 21 19 15];
m=size(x,2); %获得数据点个数
n=1;
syms symsx
f = symfun([a*exp(b*symsx),],symsx);%在这里可以修改phi(x)的表达式,如symsx^2,在建立法方程时的值为x^2,cos(symsx)则建立法方程时为cos(x)
expr = formula(f);
A=zeros(m,n); %构造法方程所需的A和Y
for j=1:n
temp =subs(expr(j),symsx,x);
temp2 = double(temp);
for i=1:m
A(i,j)=temp2(i);
end
end
Y=zeros(m,1);
for k=1:m
Y(k,1)=y(k);
end
%a=(A'*A)\(A'*Y);%左除注意
%左除即可解出a了,这里使用一下Doolittle分解法
d=Doolittle(A'*A,A'*Y);
%误差的平方和
d1=zeros(n,1);
for i=1:n
d1(i,1)=d(i);
end
c=(A*d1-Y);
Q=0;
for i=1:m
Q=Q+c(i)^2;
end
Q3=Q
plot(a*exp(b*x),'+');
legend('真值','二次多项式','三次多项式','指数函数')
Q3=3806.08212718352
即误差平方和的大小Q,Q值越小,拟合效果越好
Q1=5948.69534583064
Q2=4138.86062989298
则由Q1>Q2>Q3
得到使用指数函数拟合效果是最好的。
- 附录:Doolittle函数
function[x,y,l,u] = Doolittle(A,d)
n=size(A,1);%获得矩阵A的行数
n1=size(A,2);
m=size(d,1);
for i=1:m
b(i)=d(i,1);
end
%这里b是一个数组
u=zeros(n);%生成n*n的全零矩阵
a=zeros(n);
for i=1:n
for j=1:n1
a(i,j)=A(i,j);
end
end
l=zeros(n);
for i=1:n
l(i,i)=1;
end
for k=1:n
for j=k:n
sum1=0;
for r=1:k-1
sum1=sum1+l(k,r)*u(r,j);
end
u(k,j)=a(k,j)-sum1;
end
for i=k+1:n
sum2=0;
for r=1:k-1
sum2=sum2+l(i,r)*u(r,k);
end
l(i,k)=(a(i,k)-sum2)/u(k,k);
end
end
l
u
for i=1:n
sum3=0;
for j=1:(i-1)
sum3=sum3+l(i,j)*y(j);
end
y(i)=b(i)-sum3;
end
for i=n:-1:1%注意matlab循环变量的步进是要注明正负的
sum4=0;
for j=(i+1):n
sum4=sum4+u(i,j)*x(j);
end
x(i)=(y(i)-sum4)/u(i,i);
end
end
来源:oschina
链接:https://my.oschina.net/u/4306415/blog/3697731