最小二乘线性及平面拟合原理及C++实现

一、线性最小二乘拟合

使用一个简单函数在整体上逼近已知函数,使其在整体上尽可能与原始数据曲线近似。记为:

 称之为拟合曲线,若该函数为插值多项式,则所有偏差为零。

但实际情况中,我们不可能要求近似曲线

y =

 严格通过这么多数据点。但为了使其尽可能反映所给数据的变化趋势,我们可以要求偏差的绝对值尽可能小,甚至是所有偏差中的最大值尽可能小。我们可以通过使选取的近似曲线在节点xi 处的偏差的平方和达到最小来实现这一目标,这一原则就是 最小二乘原则。

按最小原则选择的拟合曲线就称为最小二乘拟合曲线,此方法称为最小二乘法。

实用公式推导:

 假设我们此处有这样一组数据点,这些点的分布接近于在一条直线上,因此选一条直线(一条曲线则加入对应方程推导)来拟合这组数据,令:

根据最小二乘原则,有:

 

 令a0,a1为未知数,则此处转换为求二元函数S(a0,a1)的极小点问题:

 由此可得:

 联立解得:

 

 

即得到了待求的拟合直线段。

C++实现:

bool gFittingLine(double *xArray, double *yArray, int firstIndex, int lastIndex,
				  double &a, double &b)
{
   int count = lastIndex-firstIndex+1;
    if(count < 2) return false;
    double s0 = (double)count, s1 = 0, s2 = 0, t0 = 0, t1 = 0;
    for(int i=firstIndex;i<=lastIndex;i++) 
	{
		s1 += xArray[i];
		s2 += (xArray[i]*xArray[i]);
		t0 += yArray[i];
		t1 += (xArray[i]*yArray[i]);
    }
    double d = s0*s2-s1*s1;
    b = (s2*t0-s1*t1)/d;
    a = (s0*t1-s1*t0)/d;
    return true;
}

  实现对二维平面离散点的曲线拟合

二、最小二乘面拟合

对空间中的一系列散点,寻求一个近似平面,与线性最小二乘一样,只是变换了拟合方程:

使用平面的一般方程:

Ax + By + CZ + D = 0

可以令平面方程为:

 由最小二乘法知:

 同样分别取 a0,a1,a2的偏导数:

 即是:

 换算为矩阵形式有:

 可以直接通过克拉默法则求出a0,a1,a2的行列式表达式,有:

 c++实现(gDaterm3() 为自定义的三阶行列式计算函数):

bool gFittingPlane(double *x, double *y, double *z, int n, double &a, double &b, double &c)
{
	int i;
	double x1, x2, y1, y2, z1, xz, yz, xy, r;

	x1 = x2 = y1 = y2 = z1 = xz = yz = xy = 0;
	for(i=0; i<n; i++)
	{
		x1 += x[i];
		x2 += x[i]*x[i];
		xz += x[i]*z[i];

		y1 += y[i];
		y2 += y[i]*y[i];
		yz += y[i]*z[i];

		z1 += z[i]; 
		xy += x[i]*y[i];
	}

	r = gDeterm3(x2, xy, x1, xy, y2, y1, x1, y1, n);
	if(IS_ZERO(r)) return false;

	a = gDeterm3(xz, xy, x1, yz, y2, y1, z1, y1, n) / r;
	b = gDeterm3(x2, xz, x1, xy, yz, y1, x1, z1, n) / r;
	c = gDeterm3(x2, xy, xz, xy, y2, yz, x1, y1, z1) / r;

	return true;
}

  

原文地址:https://www.cnblogs.com/zhangli07/p/12013561.html