一元线性回归-梯度下降法

在高数中,我们求解一个函数的最小值时,最常用的方法就是求出它的导数为0的那个点,进而判断这个点是否能够取最小值。但是,在实际很多情况,我们很难求解出使函数的导数为0的方程,这个时候就可以使用梯度下降。我们知道对于一个函数沿着梯度的那个方向是下降是最快的。例如为了选取一个θ使J(θ)最小,我们可以先随机选择θ一个初始值,然后不断的修改θ以减小J(θ),直到θ的值不再改变。对于梯度下降法,可以表示为:

θj=θj−α*∂J(θ)/∂θj

即不断地向梯度的那个方向(减小最快的方向)更新θ,最终使得J(θ)最小。其中α称为学习速率(learning rate),取值太小会导致迭代过慢,取值太大可能错过最值点。
假设我们有一堆数据集,这些数据集用散点图的方式,可以用一元线性回归方程表示,那么我们表示成如下公式
数据集为


image.png

假设我们建立模型 y=h(x)=θ0+θ1x
那么我们的预期是让通过对两个参数θ0和θ1的调整,将y的实际值和模型输出预测值的偏移量尽量的小,于是有

image.png

θ0和θ1两个参数的变化我们用J(θ0,θ1)表示


image.png

如何求出J(θ0,θ1)的最小值,这里就引入了梯度下降算法。主要思想是,J(θ0,θ1)好比是层峦叠嶂的群山,任意指定一个θ0和θ1,好比你在群山中的任意一个点,如何下山,一般都会瞭望四周,选择当前下山最陡的方向向下走。于是你又从A到达B,在B点,同样的情景,你将会选择下一步何去何从,同样的,选择当前最陡的路径向下走去。
如此周而复始,终将到达一个相对低,局部最优的位置。
如何将这一思想落实在数学上,是机器学习的基础。
首先先复习一下几个基本概念。
1.导数和微分

image.png

导数的定义如下

image.png

导数反映的是函数y=f(x)在某一点处沿x轴正方向的变化率。也就是在x轴上某一点处,如果f’(x)>0,说明f(x)的函数值在x点沿x轴正方向是趋于增加的;如果f’(x)<0,说明f(x)的函数值在x点沿x轴正方向是趋于减少的。

偏导数的定义

image.png

偏导数的定义和导数类似,都是当自变量的变化量趋于0时,函数值的变化量与自变量变化量比值的极限。直观地说,偏导数也就是函数在某一点上沿坐标轴正方向的的变化。区别在于导数为一元变量,偏导数为多元变量。
方向导数的定义

image.png

即:某一点在某一趋近方向上的导数值。 通俗的解释是: 我们不仅要知道函数在坐标轴正方向上的变化率(即偏导数),而且还要设法求得函数在其他特定方向上的变化率。而方向导数就是函数在其他特定方向上的变化率。

梯度的定义如下

image.png

梯度的提出只为回答一个问题:
 函数在变量空间的某一点处,沿着哪一个方向有最大的变化率? 函数在某一点的梯度是这样一个向量,它的方向与取得最大方向导数的方向一致,而它的模为方向导数的最大值。
 这里注意三点:
 1)梯度是一个向量,即有方向有大小;
 2)梯度的方向是最大方向导数的方向;
 3)梯度的值是最大方向导数的值。
既然在变量空间的某一点处,函数沿梯度方向具有最大的变化率,那么在优化目标函数的时候,自然是沿着负梯度方向去减小函数值,以此达到我们的优化目标。
 如何沿着负梯度方向减小函数值呢?既然梯度是偏导数的集合,如下

image.png

同时梯度和偏导数都是向量,那么参考向量运算法则,我们在每个变量轴上减小对应变量值即可,梯度下降法可以描述如下:  
梯度下降法

这就是梯度下降法的数据原理。
参考http://blog.csdn.net/walilk/article/details/50978864

为什么从函数的梯度方向下降可以得到函数的最小值

梯度下降法,基于这样的观察:如果实值函数F(x)在点a 处可微且有定义,那么函数 F(x)在a点沿着梯度相反的方向−▽F(a)−▽F(a)下降最快。

因而,如果

b=a−α▽F(a)
b=a−α▽F(a)
那么F(b)≤F(a)F(b)≤F(a)。

考虑如下序列x0,x1,x2,...x0,x1,x2,...使得

xn+1=xn−α▽F(xn)
xn+1=xn−α▽F(xn)
因此可以得到: F(x0)≥F(x1)≥F(x2)≥...F(x0)≥F(x1)≥F(x2)≥... 如果顺利的话序列最终可以收敛到期望的极值。
注意:梯度下降得到的结果可能是局部最优值。如果F(x)F(x)是凸函数,则可以保证梯度下降得到的是全局最优值。

批量梯度下降法的算法

批梯度下降法(batch gradient descent)的算法描述如下:

对每一个j重复以下过程直到收敛 {

image.png

}

其中假设训练样本数有m个,每个样本用zi可以表示为(xi,yi)。可以看出,使用批梯度下降法每一次更新θj都需要遍历训练样本中的所有样本。

批量梯度下降法代码
#coding=utf-8
##
#Calculate the hypothesis h = X * theta
#Calculate the loss = h - y and maybe the squared cost (loss^2)/2m
#Calculate the gradient = X' * loss / m
#Update the parameters theta = theta - alpha * gradient
###
import numpy as np
from numpy import *
import random
def loadDataSet(filename):
    numFeat = len(open(filename).readline().split(','))-1
    datMat = []; labelMat = []
    fr = open(filename)
    for line in fr.readlines():
        lineArr = []
        curLine = line.strip().split(',')
        for i in range(numFeat):
            lineArr.append(float(curLine[i]))
        datMat.append(lineArr)
        labelMat.append(float(curLine[-1]))
    return datMat,labelMat

#x为自变量训练集,y为自变量对应的因变量训练集;theta为待求解的权重值,需要事先进行初始化;alpha是学习率;m为样本总数;maxIterations为最大迭代次数;
def batchGradientDescent(x, y, theta, alpha, m, maxIterations):
    xTrains = x.transpose()   #x 转置
    for i in range(0, maxIterations):
        hypothesis = np.dot(x, theta) #矩阵乘法,https://migege.com/post/matrix-multiplication-in-numpy 计算f(x(k))
        loss = hypothesis - y
        #print(loss)
        #print(m)
        #print(type(loss))
        # avg cost per example (the 2 in 2*m doesn't really matter here.
        # But to be consistent with the gradient, I include it)
        cost = np.sum(loss ** 2) / (2 * m)
        print("Iteration %d | Cost: %f" % (i, cost))
        # avg gradient per example
        gradient = np.dot(xTrains, loss) / m  ##梯度
        #print("gradinet is ",gradient)
        # update
        theta = theta - alpha * gradient #x(k+1)
        #print("theta is ",theta)
    return theta



xArr,yArr = loadDataSet('gmvusers3.csv')
xArr1 = asarray(xArr)
yArr1 = asarray(yArr)
#print("xArr is ",asarray(xArr))
#print("yArr is ",asarray(yArr))
#print(asarray(xArr).dtype)
#print(asarray(yArr).dtype)
m, n = np.shape(xArr1)
print("m %d | n %d" %(m,n))
numIterations= 10000
alpha = 0.00000001
theta = [1,1]  #Return a new array of given shape and type, filled with ones. 初始值。
theta = batchGradientDescent(xArr1, yArr1, theta, alpha, m, numIterations)
print(theta)
####


# gen 100 points with a bias of 25 and 10 variance as a bit of noise
#x, y = genData(100, 25, 10)
#print(x)
#print(y)
#print(x.dtype)
#print(y.dtype)
#m, n = np.shape(x)
#numIterations= 100000
#alpha = 0.0001
#theta = np.ones(n)
#theta = batchGradientDescent(x, y, theta, alpha, m, numIterations)
#print(theta)


import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(yArr1,'go')

xCopy = xArr1.copy()
xCopy.sort(0)
yHat=xCopy*theta
ax.plot(xCopy[:,1],yHat)
plt.show()
print(yArr1)
print(yHat)
print(corrcoef(yHat.T,yArr1))  ???
'''
其他深度学习好的文章http://sebastianruder.com/optimizing-gradient-descent/
'''

学习速率的注意条件

参数α为初始学习速率,代表着梯度下降的速率,需要选择一个合适的参数。
在学习速率为固定值的时候,这个参数不能太小,否则学习的步数太多,程序的速度很慢,你可能需要很长一段时间才能收敛;但是也不能选的太大,
否则,你可能会发现,或许一开始J很快就接近收敛了,但是步长太大,之后并没有收敛,而是出了点状况。你会发现,代价函数的值不但迟迟不收敛,
反而可能会越来越发散,以至于结果变得糟糕起来,甚至会导致直接跨过谷底到达另一端,这就是所谓的“步子太大,迈过山谷”。至于这个参数如何选择,
需要有一定的经验,不过可以提前多选几个值做一下试验,比如用0.001,发现太慢,用0.1,发现过一段时间会发散,0.01既不太慢也不会发散,那就选择这个参数。
或者我们可以根据梯度下降每一步的实际情况动态调整学习速率,使用可变的学习速率,这就是上式的由来。我们设定一个初始的学习速率,这个学习速率也不能太大,
否则一开始就会发散,当然也不能太小,否则速度太慢。在优化的过程中,学习速率应该逐步减小,越接近“山谷”的时候,迈的“步伐”应该越小。我们每走一步,
数据分布与直线的误差越小,而这时梯度也会减小,那么步伐也就应当相应的减小,这就是初始学习速率乘上代价函数负梯度的原因。本实例中,经过我的试验,学习
速率选择为0.0001比较合适。
值得说明的是,在进行梯度下降的时候,我们应当尽量使用限定迭代次数的循环,而不是用判断是否收敛的循环。原因很简单,一旦出现你的结果是发散的,限定
迭代次数的循环可以使你的程序很快停止下来,而因为你的结果永远不会收敛,所以,如果你用while进行判断是否收敛的话,你将很有可能陷入死循环,因为你的
结果永远不可能收敛。这里我把迭代步数设为100步。
https://blog.ailemon.me/2017/02/10/machine-learningregression-statistic-model/

特征量标准化

如果我们能够将输入各个特征变量统一在相同范围内,则会加速梯度下降的效果。这是应为 θ 在小范围内将会下降的很快,在大范围内将会下降的很慢.
为了避免无谓的计算,理想状态下,我们最好能将输入变量限定在−1 ≤ x(i) ≤ 1或者−0.5 ≤ x(i) ≤ 0.5。由于目的只是为了将梯度下降效果优化,只需将各个输入X统一在一个较小的范围内即可。
一般选用两种方法:

  1. Feature scaling. X(i) 除以最大值和最小值的差,让X(i)在绝对值区间1之间.
  2. Mean normalization,公式为:xi:=xi−μisi ; μi 为 feature (i) 的均值 and si 为值的范围 (max - min), or si 为标准差。

除了批梯度下降法之外,还有一种算法称为——随机梯度下降法(stochastic gradient descent,SGD)。算法描述如下:

image.png

每一次更新只使用了一个训练样本,但更新了m次。

批梯度下降法每更新一步都需要遍历所有的样本数据,如果样本数m很大的话,就会非常的耗时;而对于随机梯度下降,每一遇到一个样本数据,就可以马上更新。通常情况下,使用随机梯度下降法的速度会比批梯度下降法快很多。因此,当样本数很大的时候,我们通常都选择使用随机梯度下降法。
参考
http://www.wengweitao.com/ti-du-xia-jiang-fa.html

另外梯度下降极容易受到异常值的影响,使用前最好删掉异常值。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容