线性回归的数学原理以及代码实现
首先要说的是线性模型想要得到的是一个线性组合。狭义的线性回归是想要把所有的点(或者叫特征)用一条直线来拟合,也就是图像上的点要尽可能地落到直线上。而广义的线性回归就不一定非要是直线了,例如在逻辑回归中用的就是一条对数几率的曲线,也就是图像上的点要尽可能的落到那条曲线上面。
在这篇文章中主要对线性回归作讨论:
首先呈上线性模型
f(x)=wTx+b
【优点】
每个x前面的w,也就是系数很直观,他们就是权重系数,当我们拟合出一个模型的时候,对于每一个x我们都能通过w知道它到底重要不重要。
【缺点】
线性模型,顾名思义,他只对线性的数据点拟合的好,而现实中存在着大量的非线性特征,拟合效果就大打折扣了。
线性回归是用梯度下降法对最小二乘误差进行优化
我们既然已经确定了任务是找到这样一条直线, f(x)=wTx+b ,使得这条直线能很好地拟合我们的样本点。那我们最理想的情况就是所有的样本点都在这条直线上,Perfect!也就是说,在这个时候,所有样本点到直线的距离为0,同时他们的距离之和也肯定为0了。
但是总归要回到现实中来,不可能有那么完美的例子,那我们只能力求他们的距离之和接近0了。或者再退一步,接近不了0也行,距离之和越小总还是越好的吧!那么就有了下面的数学表述:
用
yi
代表第i个点的真实值;
用
f(xi)
代表通过模型(函数
f
)的预测值,也就是我们的直线;
于是就有了距离的表达式:
这里用到了平方,是一种数学的技巧,为了达成下面两个目的:
+ 距离有正有负,我们这个加和的思想可不是为了抵消正负值的,所以我们必须要去掉他们的符号
+ 去掉符号也可以用绝对值,但是平方之后有一个放大的效应:如果距离不是很大,平方之后就还好,如果距离很大,平方之后就会被放的更大。(这里可以想象一下
y=x2
的函数图像,x越大,y就跟着变得更大)
【简单讲两句】:
上面这个距离表达式,学名叫做“欧式距离”,是计算距离的一种常用的数学方法,今后在机器学习其他算法中也会经常遇到。
我们继续之前的思路,就是要最小化这个距离值,由于直线由w和b决定,那么我们需要优化的参数就是w和b,换成数学语言,就是:
我们希望要距离平方和最小化的方法,称为最小二乘法。
如果从损失函数(loss function)的角度看,这个叫做“平方损失”。如果我们用
J(θ)
来表达损失函数,然后再做下面几个数学变换:
+ 令
J(θ)=12(yi−f(xi))2
argmin(w,b)∑i=1mJ(θ)=
argmin(w,b)∑i=1m12(yi−f(xi))2
在这里前面有了一个1/2的操作,纯粹了为了数学上的方便,反正在最小化的计算中,数倍的缩放没有什么影响
线性回归是残差高斯分布的最大似然估计
残差
残差就是预测值和真实值之间的差,也就是上面的
(yi−f(xi))
这一项。
我们通常认为线性回归的残差应该满足均值为0,方差为 σ2 的正态分布的假设。误差为0最好,越往两边走应该越少。
正态分布x概率表达式:
p(x)=12π√σexp[−x22σ2]
上式中的x即是线性回归的误差/残差,那么就把x替换成 (yi−f(xi)) 得到;
p((yi−f(xi)),(w,b))=12πσ√exp[−(yi−f(xi))22σ2]
接下来,我们想要达成,或者说最大限度地达成我们之间关于残差的假设,我们就必须让这个概率最大,也就是用极大似然法来求解,也就是最大化样本中每一个点分布的乘积。
L(w,b)=∏i=1m12πσ√exp[−(yi−f(xi))22σ2]
由于连乘计算难度大,我们两边都取对数,这样就变成连加:
l(w,b)=∑i=1mlog12πσ√exp[−(yi−f(xi))22σ2]
进一步化简:
l(w,b)=mlog12πσ√−1σ212∑i=1m(yi−f(xi))2
去掉一些常数项,得到我们要最大化的目标:
−12∑i=1m(yi−f(xi))2
殊途同归啊!
下面开始求解:
+ 向量化w、x和y,在这里统统用大写字母表示向量
+ 把b吸入向量w中,他们两个组合其他就是我们的参数
θ
向量化的表达方式可以让我们在接下来的运算中取消加和符号,看上去更加简便一些
argmin12(Y−θX)2
J(θ) 经过向量运算得到:
12(Y−θX)T(Y−θX)
=
12(YT−θTXT)(Y−θX)
=
12(θTXTXθ−θTXTY−YTXθ−YTY)
结果对 θ 求偏导:
【矩阵求偏导】
∂AB∂B=AT⇒YTXθ
∂ATB∂A=B⇒θTXTY
∂ATBA∂A=2AB⇒θTXTXθ
∂J(θ)∂θ=12(2XTXθ−XTY−XTY−0)=(XTXθ−XTY)
令偏导等于0:
XTXθ−XTY=0
这里暂时默认
XTX
是可逆的
得出参数 θ=(XTX)−1XTY 我们利用计算出来的参数,可以直接写出线性回归的代码来:
import numpy as np
def train(X,y):
"""训练数据"""
# 如果X^T·X是可逆的话:
if np.linalg.det(X.T * X) != 0:
# 计算参数theta
theta = ((X.T.dot(X).I).dot.(X.T).dot(y))
return theta
def test(x,theta):
"""拟合数据"""
return x.T.dot(theta)
*在本篇文章中涉及但是没有深入的概念会在后续的文章中陆续讲解,包括但不限于:
+ 极大似然法及其概率背景
+ 正则化