线性回归
基本介绍
假定数据集合中有
我们的目标是根据现有的
使得根据这条直线得到的结果与真实的结果误差最小。那么如何来衡量这个误差呢?我们引入平方损失函数,即对于样本
从数学上表述为,我们要求得
针对于最小化特定方程的,我们区分为几个section来介绍。
普通求导
根据多元函数求极值得方法,直接分别对
只有两个未知数,两个等式,因此可以解出
但是,这里面假定了样本点
这样联立线性方程组求解非常复杂.
向量求导
当未特殊说明,向量一律为列向量。
对于具有多个属性的
为了统一化,我们将
这样我们有:
此时,平均误差公式可以进一步简化为:
其中
我们的目标是求得最小化
为了对公式
对于上述的基本求导公式,它的证明只有一个思想:数对向量求导,相当于此数对向量中的各个元素逐个求导。上述的两个公式都是对列向量
上述公式的简单记忆方法: 前导不变,后导转置,公式表达为:
注意: 这里的
令
则
因此我们有:
代入
如果
上述的优化方法需要计算矩阵的逆,当数据量很小而且可逆的时候,速度快,效果好,但是并不适用于大量高维度的数据。是否有一些数学中的迭代的方式能不断的逼近最小值呢?这个答案有很多,下面将尽力逐个介绍。
梯度下降
梯度下降,顾名思义就是顺着梯度的方向的反方向下滑,直到滑动到某一个最低点为止。
我们可以把它想象成一个小山,如下图所示(
很抱歉是用latex写的,画图采用的tikz,第一次用不熟练,很丑),假定我们的起始点为start,然后顺着下山的方向,一步一步的就会滑落到它左边的最低点。
这可能会有一个问题: 如果它的右边有一个更低的最低点呢?
它有可能落不到全局最低,但是可以达到局部最低。不过,如果我们的函数是凸函数,也就是说只有一个极值点的时候,它的局部最优也就是全局最优了。
原理篇
一维直观篇
为了与高等数学教材的保持一致,采用书里面的记法,在
此后我们简单的忽略
令上图中的start点的横坐标为
为了使它向着小山下方(左面)滑动,我们需要有
那么
很显然,我们只需要
负梯度:这里面的
学习率:
上面我们说
你应该已经知道学习率为何不能太大的原因了吧,上面的描述都是基于
假定学习率
利用如上的递推公式,我们就可以不断的使得
二维梯度篇
我先从二维逐步扩展到高维的形式,二维的微分形式:
我们的目标是使得在对于自变量
那
我们令
很显然,我们应该使得
如果加上学习率,我们可以令
同样,与一维的情况一样,也是沿着负梯度的方向。
高维梯度篇
我们终于来到了高维情况,直接利用前面叙述的参数,梯度
我们有:
同样,我们应该有
梯度下降简单实现demo篇
看到这里,有没有想实现一个梯度下降的冲动,反正我是有的,因此,我用python写了一个非常非常基本的二维的梯度下降,来实现线性回归。
请稍微回到我们在section 1.1中介绍的平面图上的m个点
其中
梯度下降的4个要素:
初始值
w0=0,b0=0 学习率
α=0.01→0.0001 梯度
∂J(w,b)∂w∂J(w,b)∂b=1m∑i=0m−12(wxi+b−yi)xi=1m∑i=0m−12(wxi+b−yi) 梯度更新
wn+1bn+1=wn−α⋅∂J(w,b)∂w=bn−α⋅∂J(w,b)∂b
我们使用的数据点如下面的散点图所示,它是使用
生出散点图的python代码如下
import numpy as np
import random
import matplotlib.pyplot as plt
import pdb
random.seed(10)
x = np.arange(100)
w, b = 2, 3
y = np.array([w * i + b + random.randint(-5,5) for i in x])
one = np.ones(len(x))
plt.plot(x, y, '.')
plt.show()
利用梯度下降的4个要素编写的代码如下:
#alpha and g
alpha = 0.0003
w0, b0 = 0, 0
def gradient_w(w, b):
return np.average([2*(w*xi + b - yi)* xi for (xi, yi) in list(zip(x,y))])
def gradient_b(w, b):
return np.average([2*(w*xi + b - yi) for (xi, yi) in list(zip(x,y))])
for i in range(100000):
w1 = w0 - alpha * gradient_w(w0, b0)
b1 = b0 - alpha * gradient_b(w0, b0)
w0, b0 = w1, b1
plt.plot(x, y, 'k+')
plt.plot(x, w0 * x + b0, 'r')
plt.show()
最终迭代出的结果为:
画出的曲线如下图所示
代码其实几分钟就写完了,但是一直都拟合不出来,当时我设置的学习率为
学习率的影响:
学习率过小,导致学习速度过慢,如果设置了最大迭代次数,那么很有可能还没有学到最终结果的时候,就已经终止了。不过我们可以看到它的误差,即
学习率过大,虽然学习速度上去了,但是很有可能跳出了最优解,这可能会导致算法最终并不会收敛,误差通常会溢出。
我从网上盗取了两张图,来分别展示学习率大小对结果的影响。
对于学习率引起的问题,我给上述的梯度下降代码加入了误差计算并存储,并画出误差图。
在使用学习率
在使用学习率
根据误差图,就可以很容易指导我们是学习率不够,迭代次数不够,还是学习率过大。当误差依然处于下降的趋势,我们的迭代次数通常是不够的,如果时间不允许,那么可以稍微调整学习率,使用更大的学习率来加快收敛,但是不能过大,以免出现误差不收敛。
牛顿法
牛顿法与梯度下降法具有很大的相似性,区别在于梯度下降是采用的一阶导数,而牛顿法采用的二阶导数。
一维直观篇
请拿上我们的高等数学中的泰勒展开,采用书里面的记法,在
同样的,我们需要求得这样的
在牛顿法中,我们的泰勒展开到了
它与梯度下降很大的不同在于梯度下降的
高维原理篇
假定有n个自变量参数
我们有学习率
我们有:
利用前面学到的向量求导公式,对
然后我们就可以利用得到的
牛顿法代码Demo篇
计算
def gradient_w(w, b):
return np.average([2*(w*xi + b - yi)* xi for (xi, yi) in list(zip(x,y))])
def gradient_b(w, b):
return np.average([2*(w*xi + b - yi) for (xi, yi) in list(zip(x,y))])
def gradient_w_w(w, b):
return np.average([2 * xi * xi for (xi, yi) in list(zip(x, y))])
def gradient_w_b(w, b):
return np.average([2 * xi for (xi, yi) in list(zip(x, y))])
def gradient_b_w(w, b):
return np.average([2 * xi for (xi, yi) in list(zip(x,y))])
def gradient_b_b(w, b):
return np.average([2 for (xi, yi) in list(zip(x,y))])
def error(w, b):
return np.average([np.square(w*xi + b - yi) for (xi, yi) in list(zip(x,y))])
牛顿迭代的代码:
erros = [[], []]
for i in range(2000):
g = np.mat([gradient_w(w0, b0), gradient_b(w0, b0)]).T
G = np.mat([[gradient_w_w(w0, b0), gradient_w_b(w0, b0)], [gradient_b_w(w0, b0), gradient_b_b(w0, b0)]])
sigma = -G.I * g
w1 = w0 + sigma[0, 0]
b1 = b0 + sigma[1, 0]
erros[0].append(i)
erros[1].append(error(w1, b1))
w0, b0 = w1, b1
plt.plot(x, y, 'k+')
plt.plot(x, w0 * x + b0, 'r')
plt.show()
从误差结果看,它一次迭代就可以得到最小值,后经过@景宽提醒,牛顿法本身计算的就是二阶泰勒展开的值。我们上述的直线方程只有两个系数,它的三阶泰勒值就是0,因此二阶泰勒展开就是它的最小值了。
最小二乘法的最大似然解释
前面在Section基本介绍中,我们直接用平方损失函数来最小化来得到最优直线。那么,你是否有疑问,为什么平方损失函数最小就可以得到最优的直线,而不是绝对值损失,或者四次方损失呢?
这其实涉及到概率论中的最大似然估计.
上述的问题,可以转化为:对于
由贝叶斯公式
如果各个点相互独立,则
对于
于是,我们有:
从而最大化
另一种说法:
对于样本点
其中
一般我们认为误差服从正态分布,即
现在我们需要选取
两边取
参考文献:
https://www.cnblogs.com/21207-iHome/p/5222993.html
http://blog.csdn.net/ying_xu/article/details/51240291
https://www.cnblogs.com/happylion/p/4172632.html
http://blog.csdn.net/lydyangliu/article/details/9208635
http://www.fuzihao.org/blog/2014/06/13/为什么最小二乘法对误差的估计要用平方/