最小二乘法及算法实现

来源:互联网 发布:type3浮雕雕刻软件 编辑:程序博客网 时间:2024/06/05 11:03

最小二乘法

  • 最小二乘法
    • 线性函数模型
    • 矩阵表达形式
    • 代码

最小二乘法是一种优化方法。通过最小化误差的平方和来寻找数据的最佳函数进行匹配。

线性函数模型:

线性函数模型:

Y=B^0+B^1X

残差形式写为:

Yi=B^0+B^1X1+ei

可将ei写为

ei=YiB^0B^1X1

e_i为样本(xi,yi)的误差。
所以,平方损失函数可以表示为

Q=i=1ne2i=i=1n(YiY^i)2=i=1n(YiB^0B^1Xi)

即,使Q最小确定直线,Q可看作是以B^0,B^1为变量的Q的函数。
问题转换成一个极值问题:
再对Q求偏导。
QB^0=2ni=1(YiB^0B^1Xi)(1)=0QB^1=2ni=1(YiB^0B^1Xi)(Xi)=0

解得
B^0=X2iYiXiXiYinX2i(Xi)2B^1=nXiYiXiYinX2i(Xi)2

矩阵表达形式

Y=B^0+B^1X

推广到一般情况下,假如有更多的模型变量x1,x2,...,xm(指样本里的模型相关的变量),可以用线性函数表示如下:

y(x1,...,xm;B0,B1,...,Bm)=B0+B1x1+...+Bmxm

对于n个样本来说,可以用如下线性方程组表示:

B0+B1x11+...+Bmxm1=y1

B0+B1x12+...+Bmxm2=y2

...

B0+B1x1i+...+Bmxmi=yi

...

B0+B1x1n+...+Bmxmn=yn

将上式记为矩阵形式为:

11...1x11x21...xmn............x1nx2n...xmnB0B1...Bm=yy...yn

最终形式为
AB=Y

最小二乘形式,可以表示为:

min||ABY||2

最优解为:

B^=(ATA)1ATY

代码

/*最小二乘法的实现C++版命令行输入数据文件最后输入x得到预测的y值*/#include<iostream>#include<fstream>#include<vector>using namespace std;class LeastSquare {    double b0, b1;public:    LeastSquare(const vector<double>& x, const vector<double>& y)    {        double t1 = 0, t2 = 0, t3 = 0, t4 = 0;        for (int i = 0; i<x.size(); ++i)        {            t1 += x[i] * x[i];            t2 += x[i];            t3 += x[i] * y[i];            t4 += y[i];        }        b0 = (t1*t4 - t2*t3) / (t1*x.size() - t2*t2);        // 求得 B0        b1 = (t3*x.size() - t2*t4) / (t1*x.size() - t2*t2);  // 求得 B1     }    double getY(const double x) const    {        return b0+b1*x;    }    void print() const    {        if (b1>=0)            cout << "y = " << b0 << "+" << b1 << 'x' << "\n";        else            cout << "y = " << b0 << "" << b1 << 'x' << "\n";    }};int main(int argc, char *argv[]){    if (argc != 2)    {        cout << " data.txt don't exit " << endl;        return -1;    }    else    {        vector<double> x;        vector<double> y;        int count = 1;        ifstream in(argv[1]);        for (double d; in >> d; count++)            if (count % 2 == 1)                x.push_back(d);            else                y.push_back(d);        LeastSquare ls(x, y);        ls.print();        cout << "Input x:\n";        double x0;        while (cin >> x0)        {            cout << "y = " << ls.getY(x0) << endl;            cout << "Input x:\n";        }    }    int endline;    cin >> endline;}

int main(int argc,char* argv[])
argc是命令行总的参数个数,argv[]是argc个参数,其中第0个参数是程序的全名,以后的参数命令行后面跟的用户输入的参数
比如:
int main(int argc, char* argv[])
{

}

两种方法:
第一种:
无需调试的情况:
直接用dos命令进入到.exe目录下然后输入:*.exe pra1 pra2
第二种:
需要调试的情况:
i.先选择项目-〉右键-〉属性
ii.调试 -〉命令行参数
在命令行参数里面输入命令行参数即可。
需要注意的是,不需要像第一种那样样输入*.exe了。只需要输入 pra1 pra2 ,中间用空格隔开。

例如:以上实现代码,需要输入一个data.txt,输入格式是(x,y)的点值。1 02 1 3 2 0 1 1 2 2 3
原创粉丝点击