最小二乘法的一般形式和矩阵形式原理推导和代码实现
2017-01-13 21:52
555 查看
转自:作者:金良(golden1314521@gmail.com) csdn博客:http://blog.csdn.NET/u012176591
![](https://oscdn.geek-share.com/Uploads/Images/Content/201701/9e657da5892b57dc63ffe5f5cf3f7108)
推导过程:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201701/23167e98fb33498c7309e42ad7191ab5)
条件:
矩阵
![](https://oscdn.geek-share.com/Uploads/Images/Content/201701/ae30a9df0ade63acdf6d49ea0de9b676)
必须是列满秩矩阵,否则
![](https://oscdn.geek-share.com/Uploads/Images/Content/201701/31a867b632898a19646086f46ee5aa1f)
的逆就不会存在。
若A为m×n的矩阵,b为m×1的矩阵,则Ax=b表达了一个线性方程组,它的normal equation的形式为ATAx=ATb。
当Ax=b有解时(即矩阵[A|b]的秩与A的秩相同),Ax=b与ATAx=ATb的解集是一样。
而当Ax=b无解时,ATAx=ATb仍然有解,其解集即最小二乘解(least squares solution),即使得(Ax-b)T(Ax-b)的值最小的解,可以理解为使方程组Ax=b近似成立且误差最小的解。
Python语言写的一个例子:
[python] view
plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
#encoding=UTF-8
'''''
Created on 2014年6月30日
@author: jin
'''
from numpy import *
import matplotlib.pyplot as plt
from random import *
def loadData():
x = arange(-1,1,0.02)
y = ((x*x-1)**3+1)*(cos(x*2)+0.6*sin(x*1.3))
#生成的曲线上的各个点偏移一下,并放入到xa,ya中去
xr=[];yr=[];i = 0
for xx in x:
yy=y[i]
d=float(randint(80,120))/100
i+=1
xr.append(xx*d)
yr.append(yy*d)
return x,y,xr,yr
def XY(x,y,order):
X=[]
for i in range(order+1):
X.append(x**i)
X=mat(X).T
Y=array(y).reshape((len(y),1))
return X,Y
def figPlot(x1,y1,x2,y2):
plt.plot(x1,y1,color='g',linestyle='-',marker='')
plt.plot(x2,y2,color='m',linestyle='',marker='.')
plt.show()
def Main():
x,y,xr,yr = loadData()
X,Y = XY(x,y,9)
XT=X.transpose()#X的转置
B=dot(dot(linalg.inv(dot(XT,X)),XT),Y)#套用最小二乘法公式
myY=dot(X,B)
figPlot(x,myY,xr,yr)
Main()
程序截图:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201701/48e2d94b7730a5c3ce85dceebe331346)
MATLAB写的例子:
[plain] view
plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
clear
clc
Y=[33815 33981 34004 34165 34212 34327 34344 34458 34498 34476 34483 34488 34513 34497 34511 34520 34507 34509 34521 34513 34515 34517 34519 34519 34521 34521 34523 34525 34525 34527]
T=[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30]
% 线性化处理
for t = 1:30,
x(t)=exp(-t);
y(t)=1/Y(t);
end
% 计算,并输出回归系数B
c=zeros(30,1)+1;
X=[c,x'];
B=inv(X'*X)*X'*y'
for i=1:30,
% 计算回归拟合值
z(i)=B(1,1)+B(2,1)*x(i);
end
Y2=[]
for j=1:30,
Y2(j)=1/(B(1,1)+B(2,1)*exp(-j));
end
plot(T,Y2)
hold on
plot(T,Y,'r.')
截图:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201701/9410524cdf0be4a9993d235ecd3dbfd6)
以简单线性模型 y = b1t +b0 作为例子。
回归模型:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201701/3c7e195ac9c66ef54f661b408630934c)
最优化目标函数:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201701/3ed57654cef9891ce5713e06c6fd586b)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201701/588b3f4eb704a34a64953a0aacd4d2e4)
则目标函数可以简化成如下形式:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201701/3ec21b60eba868779194ccac4cb54b95)
对简化后的目标函数进行求解,得到
![](https://oscdn.geek-share.com/Uploads/Images/Content/201701/051bd4d01a2315914b56b07031f9d6e7)
表达式:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201701/8630837da357aa2ddcc12def7df87e11)
下面是C++的实现例子:
[cpp] view
plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
#include<iostream>
#include<fstream>
#include<vector>
#include<cstdlib>
#include<ctime>
using namespace std;
class LeastSquare{
double b0, b1;
public:
LeastSquare(const vector<double>& x, const vector<double>& y)
{ //下面是最小二乘法的核心过程
double xi_xi=0, xi=0, xi_yi=0, yi=0;
for(int i=0; i<x.size(); ++i)
{
xi_xi += x[i]*x[i];
xi += x[i];
xi_yi += x[i]*y[i];
yi += y[i];
}
b1= (xi_yi*x.size() - xi*yi) / (xi_xi*x.size() - xi*xi);
b0 = (xi_xi*yi - xi*xi_yi) / (xi_xi*x.size() - xi*xi);
}
double getY(const double x) const
{
return b0+b1*x;
}
void print() const
{
cout<<"y = "<<b0<<"+"<<b1<<"x "<<"\n";
}
};
int main()
{
srand((unsigned int)(time(NULL)));//
vector<double> x,y;
double xi = 0,yi,xin,xout;
for (int i = 0;i <10; i++) {
yi = 2*xi +1;//原模型
yi += 0.05*rand()/RAND_MAX*yi;//添加噪声
y.push_back(yi);
x.push_back(xi);
xi += 5.0;
}
LeastSquare lsObj(x, y);//用样本数据实例化对象
lsObj.print(); //输出最小二乘法得到的模型
cout<<"Input x:\n";
while(cin>>xin)
{
xout = lsObj.getY(xin);//利用得到的模型计算因变量
cout<<"y = "<<xout<<endl;
cout<<"Input x:\n";
}
}
执行效果截图:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201701/2a3df3f844821ad1aed940b8eb5050b3)
1 、本质相同:两种方法都是在给定已知数据(因变量 & 自变量)的前提下对因变量算出出一个一般性的估值函数。然后对给定的新的自变量用估值函数对其因变量进行估算。
2、 目标相同:都是在已知数据的框架内,使得估算值与实际值的差的平方和尽量更小(事实上未必一定要使用平方),估算值与实际值的差的平方和的公式为:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201701/6366509f9421045bb0f58e63ca2fcc0c)
不同点:
1、实现方法和结果不同:
最小二乘法是直接对error求导找出全局最小,是非迭代法。
而梯度下降法是一种迭代法,有一个学习的过程,先由给定参数计算一个error,然后向该error下降最快的方向调整参数值,在若干次迭代之后找到局部最小。
梯度下降法的缺点是到最小点的时候收敛速度变慢,并且对初始点的选择极为敏感,其改进大多是在这两方面下功夫。
1.线性代数模型
首先给出最小二乘解的矩阵形式的公式:推导过程:
条件:
矩阵
必须是列满秩矩阵,否则
的逆就不会存在。
若A为m×n的矩阵,b为m×1的矩阵,则Ax=b表达了一个线性方程组,它的normal equation的形式为ATAx=ATb。
当Ax=b有解时(即矩阵[A|b]的秩与A的秩相同),Ax=b与ATAx=ATb的解集是一样。
而当Ax=b无解时,ATAx=ATb仍然有解,其解集即最小二乘解(least squares solution),即使得(Ax-b)T(Ax-b)的值最小的解,可以理解为使方程组Ax=b近似成立且误差最小的解。
Python语言写的一个例子:
[python] view
plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
#encoding=UTF-8
'''''
Created on 2014年6月30日
@author: jin
'''
from numpy import *
import matplotlib.pyplot as plt
from random import *
def loadData():
x = arange(-1,1,0.02)
y = ((x*x-1)**3+1)*(cos(x*2)+0.6*sin(x*1.3))
#生成的曲线上的各个点偏移一下,并放入到xa,ya中去
xr=[];yr=[];i = 0
for xx in x:
yy=y[i]
d=float(randint(80,120))/100
i+=1
xr.append(xx*d)
yr.append(yy*d)
return x,y,xr,yr
def XY(x,y,order):
X=[]
for i in range(order+1):
X.append(x**i)
X=mat(X).T
Y=array(y).reshape((len(y),1))
return X,Y
def figPlot(x1,y1,x2,y2):
plt.plot(x1,y1,color='g',linestyle='-',marker='')
plt.plot(x2,y2,color='m',linestyle='',marker='.')
plt.show()
def Main():
x,y,xr,yr = loadData()
X,Y = XY(x,y,9)
XT=X.transpose()#X的转置
B=dot(dot(linalg.inv(dot(XT,X)),XT),Y)#套用最小二乘法公式
myY=dot(X,B)
figPlot(x,myY,xr,yr)
Main()
程序截图:
MATLAB写的例子:
[plain] view
plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
clear
clc
Y=[33815 33981 34004 34165 34212 34327 34344 34458 34498 34476 34483 34488 34513 34497 34511 34520 34507 34509 34521 34513 34515 34517 34519 34519 34521 34521 34523 34525 34525 34527]
T=[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30]
% 线性化处理
for t = 1:30,
x(t)=exp(-t);
y(t)=1/Y(t);
end
% 计算,并输出回归系数B
c=zeros(30,1)+1;
X=[c,x'];
B=inv(X'*X)*X'*y'
for i=1:30,
% 计算回归拟合值
z(i)=B(1,1)+B(2,1)*x(i);
end
Y2=[]
for j=1:30,
Y2(j)=1/(B(1,1)+B(2,1)*exp(-j));
end
plot(T,Y2)
hold on
plot(T,Y,'r.')
截图:
2、一般线性模型
一般线性模型,即普通最小二乘法( Ordinary Least Square,OLS):所选择的回归模型应该使所有观察值的残差平方和达到最小。以简单线性模型 y = b1t +b0 作为例子。
回归模型:
最优化目标函数:
则目标函数可以简化成如下形式:
对简化后的目标函数进行求解,得到
表达式:
下面是C++的实现例子:
[cpp] view
plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
#include<iostream>
#include<fstream>
#include<vector>
#include<cstdlib>
#include<ctime>
using namespace std;
class LeastSquare{
double b0, b1;
public:
LeastSquare(const vector<double>& x, const vector<double>& y)
{ //下面是最小二乘法的核心过程
double xi_xi=0, xi=0, xi_yi=0, yi=0;
for(int i=0; i<x.size(); ++i)
{
xi_xi += x[i]*x[i];
xi += x[i];
xi_yi += x[i]*y[i];
yi += y[i];
}
b1= (xi_yi*x.size() - xi*yi) / (xi_xi*x.size() - xi*xi);
b0 = (xi_xi*yi - xi*xi_yi) / (xi_xi*x.size() - xi*xi);
}
double getY(const double x) const
{
return b0+b1*x;
}
void print() const
{
cout<<"y = "<<b0<<"+"<<b1<<"x "<<"\n";
}
};
int main()
{
srand((unsigned int)(time(NULL)));//
vector<double> x,y;
double xi = 0,yi,xin,xout;
for (int i = 0;i <10; i++) {
yi = 2*xi +1;//原模型
yi += 0.05*rand()/RAND_MAX*yi;//添加噪声
y.push_back(yi);
x.push_back(xi);
xi += 5.0;
}
LeastSquare lsObj(x, y);//用样本数据实例化对象
lsObj.print(); //输出最小二乘法得到的模型
cout<<"Input x:\n";
while(cin>>xin)
{
xout = lsObj.getY(xin);//利用得到的模型计算因变量
cout<<"y = "<<xout<<endl;
cout<<"Input x:\n";
}
}
执行效果截图:
3.最小二乘法和梯度下降算法
相同点:1 、本质相同:两种方法都是在给定已知数据(因变量 & 自变量)的前提下对因变量算出出一个一般性的估值函数。然后对给定的新的自变量用估值函数对其因变量进行估算。
2、 目标相同:都是在已知数据的框架内,使得估算值与实际值的差的平方和尽量更小(事实上未必一定要使用平方),估算值与实际值的差的平方和的公式为:
不同点:
1、实现方法和结果不同:
最小二乘法是直接对error求导找出全局最小,是非迭代法。
而梯度下降法是一种迭代法,有一个学习的过程,先由给定参数计算一个error,然后向该error下降最快的方向调整参数值,在若干次迭代之后找到局部最小。
梯度下降法的缺点是到最小点的时候收敛速度变慢,并且对初始点的选择极为敏感,其改进大多是在这两方面下功夫。
相关文章推荐
- 最小二乘法的一般形式和矩阵形式原理推导和代码实现
- 基于矩阵分解推荐算法之交替最小二乘法(ALS)--附实现代码
- 最小二乘法(一般形式和矩阵形式)
- 转置矩阵的分块并行乘法(C语言实现),计算矩阵C[rawn][rawn]=A[rawm][rawn]'*B[rawm][rawn],子块大小为S*T,其算法实现原理参加本代码的附件。
- 有限域GF(2^8)内乘法代码实现以及原理
- Coursera deeplearning.ai 深度学习笔记1-3-Shallow Neural Networks-浅层神经网络原理推导与代码实现
- triplet loss原理推导及其代码实现
- 【甘道夫】MapReduce实现矩阵乘法--实现代码
- BP神经网络原理简单介绍以及公式推导(矩阵形式和分量形式)
- Coursera deeplearning.ai 深度学习笔记1-4-Deep Neural Networks-深度神经网络原理推导与代码实现
- 线性代数教程之一——矩阵乘法计算、理解及代码实现
- 有限域GF(2^8)内乘法代码实现以及原理
- 最小二乘法 多项式曲线拟合 原理公式理解 Python 实现
- 3D光照阴影 平面阴影矩阵推导及代码实现
- 深度学习|反向传播算法(BP)原理推导及代码实现
- 最大流/最小割(maxflow/mincut)的原理讲解和代码实现
- 最小二乘法C#实现,简单代码
- MapReduce实现大矩阵乘法及代码实现
- 算法导论,动态规划 —— 矩阵链乘法(python代码实现示例)
- Coursera deeplearning.ai 深度学习笔记1-2-Neural Network Basics-逻辑回归原理推导与代码实现