【C++】线性拟合、指数曲线拟合的最小二乘法作业

本文介绍了曲线拟合的最小二乘法,通过选择合适的函数类型和权系数,寻找使偏差平方和最小的拟合曲线。文中通过例题3.7展示了线性函数的拟合,以及例题3.8中使用指数曲线拟合,讨论了两种不同的实现方式,强调了数据预处理和矩阵运算在求解过程中的作用。
摘要由CSDN通过智能技术生成

曲线拟合的最小二乘法

引入

  • 对于未知的函数 y = f ( x ) y=f(x) y=f(x),已知一些节点数据 A m ( x i , y i ) A_m(x_i,y_i) Am(xi,yi),希望构建函数 y = φ ( x ) y=φ(x) y=φ(x)逼近 y = f ( x ) y=f(x) y=f(x)

  • 在插值中,一般严格要求在每个插值节点处都没有偏差,都满足 δ i = φ ( x i ) − f ( x i ) = 0 δ_i=φ(x_i)-f(x_i)=0 δi=φ(xi)f(xi)=0;而有时候拟合时允许在节点处有偏差,但总的偏差应该尽可能小。

  • 可以使偏差的绝对值之和尽可能小,但为了方便计算,采用偏差的平方和,即 ∑ i = 1 m [ φ ( x i ) − f ( x i ) ] 2 \displaystyle\sum_{i=1}^{m}{[φ(x_i)-f(x_i)]^2} i=1m[φ(xi)f(xi)]2尽可能小。

  • 按此原则构建拟合曲线 y = φ ( x ) y=φ(x) y=φ(x)的方法,称为曲线拟合的最小二乘法。

丰富

考虑计算方便和实际意义,进行两处的丰富:

  1. φ ( x ) φ(x) φ(x)的函数类型需要提前选取好。
    常常在简单函数中选取,如代数多项式或三角多项式。
    可以选好 n ( n < m ) n(n<m) n(n<m)个函数 φ i ( x ) φ_i(x) φi(x),构成 φ ( x ) = a 0 φ 0 ( x ) + a 1 φ 1 ( x ) + . . . + a n φ n ( x ) φ(x)=a_0φ_0(x)+a_1φ_1(x)+...+a_nφ_n(x) φ(x)=a0φ0(x)+a1φ1(x)+...+anφn(x) a i a_i ai为参数,后续需要求解。

  2. 节点数据 A m A_m Am的重要性有时不同。
    有必要添加权系数 ω i > 0 ω_i>0 ωi>0,使得 ∑ i = 1 m ω i [ φ ( x i ) − f ( x i ) ] 2 \displaystyle\sum_{i=1}^{m}{ω_i[φ(x_i)-f(x_i)]^2} i=1mωi[φ(xi)f(xi)]2最小。

综上,根据最小二乘问题: ∑ i = 1 m ω i [ φ ( x i ) − f ( x i ) ] 2 \displaystyle\sum_{i=1}^{m}{ω_i[φ(x_i)-f(x_i)]^2} i=1mωi[φ(xi)f(xi)]2最小,求出的 φ ( x ) = a 0 φ 0 ( x ) + a 1 φ 1 ( x ) + . . . + a n φ n ( x ) φ(x)=a_0φ_0(x)+a_1φ_1(x)+...+a_nφ_n(x) φ(x)=a0φ0(x)+a1φ1(x)+...+anφn(x)则是该最小二乘问题的最小二乘解。

求解

φ i ( x ) φ_i(x) φi(x)人为选取后,需要求解 φ ( x ) = a 0 φ 0 ( x ) + a 1 φ 1 ( x ) + . . . + a n φ n ( x ) φ(x)=a_0φ_0(x)+a_1φ_1(x)+...+a_nφ_n(x) φ(x)=a0φ0(x)+a1φ1(x)+...+anφn(x)中的参数 a i a_i ai来确定 φ ( x ) φ(x) φ(x)的形式,即是求多元函数 S ( a 0 , a 1 , . . . a n ) = ∑ i = 1 m ω i [ ∑ k = 0 n a k φ k ( x i ) − f ( x i ) ] 2 S(a_0,a_1,...a_n)=\displaystyle\sum_{i=1}^{m}{ω_i[\displaystyle\sum_{k=0}^{n}{a_kφ_k(x_i)}-f(x_i)]^2} S(a0,a1,...an)=i=1mωi[k=0nakφk(xi)f(xi)]2的极小值点。

由多元函数求极小值的必要条件,有 ∂ S ∂ a j = 0 , j = 0 , 1 , . . . , n \displaystyle\frac{∂S}{∂a_j}=0, j=0,1,...,n ajS=0,j=0,1,...,n

求偏导后,即
在这里插入图片描述
移项,即
在这里插入图片描述
下面是推导过程,看懂即可,此处不再手打。关于下图中的离散点集的内积,类似函数的内积,也就是两个函数在每个离散点处乘积的累加。由于离散,所以只在节点处累加,如果是函数,则是在定义域积分,可看作无数离散点、无数次累加。
不过,下图中写成内积形式,是为了以简洁的形式写出(3.5.9)的矩阵;不以简洁形式则类似公式(3.5.11)的形式,不过(3.5.11)代入了选取的 φ i ( x ) φ_i(x) φi(x)
在这里插入图片描述
选取 φ i ( x ) = x i , i = 0 , 1 , . . . , n . φ_i(x)=x^i,i=0,1,...,n. φi(x)=xi,i=0,1,...,n.
在这里插入图片描述

在这里插入图片描述
为了简单地编写下面的作业,只需要利用公式(3.5.11)中的矩阵。

例题3.7:直线拟合

题目介绍

在这里插入图片描述

编程之前

对于线性函数的拟合,n=1,只需要取法方程组的前两行两列来计算a0和a1。

在这里插入图片描述
然后可以再利用前面一篇中求解线性方程组中的函数来求出 ( a 0 , a 1 ) (a_0,a_1) (a0,a1)

代码

//数据准备:x、y为已知的节点数据,w为权重数据,m为节点数
void PreapreDatasetA1(vector<double>& x, vector<double>& y, 
	vector<double>& w, int& m) {
	m = 5;
	x = { 1,2,3,4,5 };
	y = { 1.2,2.7,5.3,7.1,8.5 };
	w = { 2,1,1,3,1 };
}

//线性拟合:x、y为已知的节点数据,w为权重数据,m为结点数
void LinearFitting(vector<double> x, vector<double> y, 
	vector<double> w, int m) {
	//MA=B
	vector<vector<double>> M;//图3.5.11中的第1个矩阵,从左往右
	//矩阵初始化
	vector<double> r1 = { 0,0 };
	vector<double> r2 = { 0,0 };
	M.push_back(r1);
	M.push_back(r2);

	vector<double> A = { 0, 0 };//图3.5.11中的第2个矩阵
	vector<double> B = { 0, 0 };//图3.5.11中的第3个矩阵

	//计算出矩阵M和B
	for (int i = 0; i < m;i++) {
		M[0][0] += w[i];
		M[0][1] += w[i] * x[i];
		M[1][0] += w[i] * x[i];
		M[1][1] += w[i] * x[i] * x[i];
		B[0] += w[i] * y[i];
		B[1] += w[i] * x[i] * y[i];
	}

	//高斯消元
	GaussElimination_Sequence(M, n, B);

	//回代上三角
	CalcUpperTraiangularMatrix(M, n, B, A);

	cout << "计算结果:y="<< A[0]  << "+" << A[1] << "x" << endl;

}

void LineFittingTest() {
	vector<double> x, y, w;
	int m;
	PreapreDatasetA1(x, y, w, m);
	LinearFitting(x, y, w, m);
	
	cout << "H";
}

例题3.8:指数曲线拟合

题目介绍

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码

方式1

或许可以直接偷懒改一下输入数据,为表3.3,那么也就和上一题一样了:

void PreapreDatasetA2(vector<double>& x, vector<double>& y, 
	vector<double>& w, int& m) {
	m = 9;
	x = { 1,2,3,4,5,6,7,8,9 };
	y = { 0.25,0.35,0.438,0.573,0.648,0.725,0.84,0.947,1.04 };
	w = { 1,1,1,1,1,1,1,1,1, };
}

输出时修改一下打印方式:

cout << "计算结果:u="<< A[0]  << "+" << A[1] << "x" << endl;
cout << "计算结果:y=10^(" << A[0] << "+" << A[1] << "x)" << endl;

方式2

也可以输入表3.2的数据,根据 ( x i , y i ) (x_i,y_i) (xi,yi),先取对数,求出 u i u_i ui(计算出表3.3的数据,保留的位数不同,精度也不同),再进行线性拟合。

void PreapreDatasetB1(vector<double>& x, vector<double>& y, 
	vector<double>& w, int& m) {
	m = 9;
	x = { 1,2,3,4,5,6,7,8,9 };
	y = { 1.78,2.24,2.74,3.74,4.45,5.31,6.92,8.85,10.97 };
	w = { 1,1,1,1,1,1,1,1,1, };

	for (int i = 0; i < m; i++)
	{
		y[i] = log10(y[i]);
	}
}
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值