登录
首页大数据时代机器学习中最小二乘法是什么,如何实现?
机器学习中最小二乘法是什么,如何实现?
2020-07-24
收藏

最小二乘法,相信大家都不陌生,统计学中很是常见,而且其理论相对简单,用途也很广泛。今天小编就给大家具体介绍一下最小二乘法。

一、最小二乘概念

最小二乘,或者也可以叫做最小平方和,它目的就是通过最小化误差的平方和,使得拟合对象无限接近目标对象。也就意味着,最小二乘法可以用于对函数的拟合。

最小二乘法是勒让德( A. M. Legendre)于1805年在其著作《计算慧星轨道的新方法》中提出的。

线性回归中,最小二乘法就是试图找到一条直线,使所有样本到直线的欧氏距离之和最小。更直观的解释:

假设有一条直线y=ax+b,要在这条直线上找到一点,距离(x0.y0)这个点的距离最短。如果用绝对值的方法寻找,也就是取min(|y−y0|+|x−x0|),由于绝对值最小为0.所以最小的情况就是x=x0或者y=y0处。

如果用平方和的方法寻找,就是取min(y−y0)2+(x−x0)2.可以看出该式是两点间距离公式,也就是距离的概念。那么最短的距离,就是点到直线的垂线。

二、最小二乘核心思想

最小二乘的主要思想就是求解未知参数,使得理论值与观测值之差(即误差,或者说残差)的平方和达到最小:

三、直线拟合/多元线性回归

求导计算最小值是通用解法,但矩阵法比代数法要简洁,且矩阵运算可以取代循环,所以现在很多书和机器学习库都是用的矩阵法来做最小二乘法。

损失函数定义为:(系数1/2是为了简化计算添加的,求迹前和求迹后值不变)

应用矩阵迹的计算公式:

四、最小二乘法的适用场景

当样本量m很少,小于特征数n的时候,这时拟合方程是欠定的,需要使用LASSO。当m=n时,用方程组求解。当m>n时,拟合方程是超定的,可以使用最小二乘法。

但是同时最小二乘也具有局限性:

1.最小二乘法需要计算(XTX)−1逆矩阵,有可能逆矩阵不存在,这样就没有办法直接用最小二乘法。

2.如果是样本特征n非常的大的情况,计算逆矩阵是一个极为耗时的工作,甚至是不可行,通常不超过10000个特征

3.若拟合函数不是线性的,则无法使用最小二乘法,这时就需要通过一些技巧转化为线性才能使用。

五、最小二乘实现


/*
最小二乘法的实现
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;
}


数据分析咨询请扫描二维码

客服在线
立即咨询