您的位置:首页 > 编程语言 > C语言/C++

最小二乘法直线拟合(C++)

2013-12-12 10:41 423 查看
1.原理

在现实中经常遇到这样的问题,一个函数并不是以某个数学表达式的形式给出,而是以一些自变量与因变量的对应表给出,老师讲课的时候举的个例子是犯罪人的身高和留下的脚印长,可以测出一些人的数据然后得到一张表,它反应的是一个函数,回归的意思就是将它还原成数学表达式,这个式子也称为经验表达式,之所以叫经验就是说它不完全是实际中的那样准确,是有一定偏差的,只是偏差很小罢了。

最小二乘法

设经验

方程是y=F(x),方程中含有一些待定系数an,给出真实值{(xi,yi)|i=1,2,...n},将这些x,y值代入方程然后作

差,可以描述误差:yi-F(xi),为了考虑整体的误差,可以取平方和,之所以要平方是考虑到误差可正可负直接相加可以相互抵消,所以记误差为:

e=∑(yi-F(xi))^2

它是一个多元函数,有an共n个未知量,现在要求的是最小值。所以必然满足对各变量的偏导等于0,于是得到n个方程:

de/da1=0

de/da2=0

...

de/dan=0

n个方程确定n个未知量为常量是理论上可以解出来的。用这种误差分析的方法进行回归方程的方法就是最小二乘法。

线性回归

如果经验方程是线性的,形如y=ax+b,就是线性回归。按上面的分析,误差函数为:

e=∑(yi-axi-b)^2

各偏导为:

de/da=2∑(yi-axi-b)xi=0

de/db=-2∑(yi-axi-b)=0

于是得到关于a,b的线性方程组:

(∑xi^2)a+(∑xi)b=∑yixi

(∑xi)a+nb=∑yi

设A=∑xi^2,B=∑xi,C=∑yixi,D=∑yi,则方程化为:

Aa+Bb=C

Ba+nb=D

解出a,b得:

a=(Cn-BD)/(An-BB)

b=(AD-CB)/(An-BB)


这就是我们要进行的算法。

2.C++实现

/*

* =====================================================================================

*

* Filename: nihe.cpp

*

* Description: A least square method for fitting a curve

*

* Version: 1.0

* Created: 03/21/2009 12:32:56 PM

* Revision: none

* Compiler: gcc

*

* Author: Futuredaemon (BUPT), gnuhpc@gmail.com

* Company: BUPT_UNITED

*

* =====================================================================================

*/

#include <stdlib.h>

#include <iostream>

#include <valarray>

using namespace std;

int main(int argc, char *argv[])

{

int num = 0;

cout << " Input how many numbers you want to calculate:";

cin >> num;

valarray<double> data_x(num);

valarray<double> data_y(num);

while( num )

{

cout << "Input the "<< num <<" of x:";

cin >> data_x[num-1];

cout << "Input the "<< num <<" of y:";

cin >> data_y[num-1];

num--;

}

double A =0.0;

double B =0.0;

double C =0.0;

double D =0.0;

A = (data_x*data_x).sum();

B = data_x.sum();

C = (data_x*data_y).sum();

D = data_y.sum();

double k,b,tmp =0;

if(tmp=(A*data_x.size()-B*B))

{

k = (C*data_x.size()-B*D)/tmp;

b = (A*D-C*B)/tmp;

}

else

{

k=1;

b=0;

}

cout <<"k="<<k<<endl;

cout <<"b="<<b<<endl;

return 0;

}

3.OpenCV结构实现

#include "cv.h"

#include <iostream>

using namespace std;

int main(int argc, char *argv[])

{

int i=0;

int j=0;

int num;

double A,B,C,D;

double k,b,tmp=0;

cout <<"Input how many numbers you want to calculate:";

cin >>num;

CvMat *mat1=cvCreateMat(1,num,CV_64FC1);

CvMat *mat2=cvCreateMat(1,num,CV_64FC1);

CvMat *mattmp=cvCreateMat(1,num,CV_64FC1);

for (j=0;j<mat1->cols;j++)

{

cout << "data X"<<j<<"=";

cin>>CV_MAT_ELEM(*mat1,double,0,j);

cout << "data Y"<<j<<"=";

cin>>CV_MAT_ELEM(*mat2,double,0,j);

}

for (j=0;j<mat1->cols;j++)

{

cout<<"X="<<CV_MAT_ELEM(*mat1,double,0,j)

<<",Y="<<CV_MAT_ELEM(*mat2,double,0,j)<<endl;

}

cvMul(mat1,mat1,mattmp,1);

A = cvSum(mattmp).val[0];

B = cvSum(mat1).val[0];

cvMul(mat1,mat2,mattmp,1);

C = cvSum(mattmp).val[0];

D = cvSum(mat2).val[0];

tmp = A*mat1->cols-B*B;

k = (C*mat1->cols-B*D)/tmp;

b = (A*D-C*B)/tmp;

cout << "k=" << k <<endl;

cout << "b=" << b <<endl;

cvReleaseMat(&mat1);

cvReleaseMat(&mat2);

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: