一元线性回归(1):批量梯度下降法、Python代码实现

机器学习(2)


初见线性回归中,说到了:“显然不是什么歪瓜裂枣都能符合”今天就来介绍选择回归方程的方法之一:梯度下降法。
在这里插入图片描述

一元线性回归方程

我们往往会得到形如y = kx + b的各种方程,此时我们就需要性能度量来评价这个方程的优劣:
在这里插入图片描述
在这里,为了接下来的计算方便,我们选用如下公式:
在这里插入图片描述
接下来将分别以y = kx 和 y = kx + b两种方程介绍批量梯度下降法:

y = kx

梯度下降

在这里插入图片描述
现有ABCDE五个点作为训练集,以及fgh t pqs七个不同的方程,其斜率分别为:
1.6 / 1.5 / 1.2/ 1 / 0.8 / 0.5 / 0.4
我们要找到最符合这个训练集的线性回归方程,分别用这7个方程代入前文公式计算结果:(结果记为E)
在这里插入图片描述
得到六组数据(k,E):

k E
1.6 1.980
1.5 1.375
1.2 0.220
1 0.000
0.8 0.220
0.5 1.375
0.4 1.980

我们在座标轴上画出这七个点:
在这里插入图片描述
不难发现,这些点似乎是在一条类似抛物线的曲线上。
在这里插入图片描述
并且,当k等于1的时候,E才有最小值:0。而梯度下降的目的就是,找到这个最小的E ,从而找到最符合训练集的线性回归方程

怎么让E最小?——梯度下降法

梯度下降法的原理就是,将每个数据代入公式计算出E,若E过大,则增加/减少k值,再重新将每个数据代入公式计算出E,直到找到一个k,使E的值最小或者在我们允许的范围内。(白话)

“梯度”是什么?

我们将E的计算公式对k求偏导数,所得结果就叫做“梯度”
在这里插入图片描述
在这里插入图片描述

怎么实现梯度下降?

在这里插入图片描述
(我的数学公式软件不支持α等希腊字母,这里用a代替了,其实都一样的。)
其中,k是当前的斜率,E对k的偏导数就是前文提到的“梯度”,而α就是学习率
由此,便能够实现让k不断增大/减小使得程序最终能找到一个最小的或在我们允许的最小范围内的E。

学习率——α的选定

学习率α是我们自己选定的数,1、0.1 、 0.05等等均可。在设置好α以后,我们并不需要让程序自己去改动它,因为每次迭代完成,E对k的偏导都会变小,使k每次减小的幅度都会比上一次要小:

在这里插入图片描述
所以,当本次E与上一次E的差值在我们期望的区间里时,就可以认为当前的E是一个比较合适的值

这里要注意的是,α不是一个随便就能用的数

若α过小

直观感受如图:
在这里插入图片描述
而体现在程序中,则代表着需要循环特别多次才能找到最小的E:
在这里插入图片描述

若α过大

α过大则会无法收敛,如图:
在这里插入图片描述
在程序中则体现为:
在这里插入图片描述
所以,α的取值也是很重要的/doge

代码实现

我们已经知道了E会不断减小并且减小的幅度会越来越小。所以,当本次E与上一次E的差值在我们期望的区间里时,就可以认为当前的E是一个比较合适的值

x = [1,2,3,4,5]#自定义ABCDE的横座标
y = [1,2,3,4,5]#自定义ABCDE的纵座标

error = 0.00001 #我们允许的 两次E的差的范围
a = 0.01 #学习率
err = 0 #初始化 f(xi)-yi 的值
E = 0 #前文计算性能度量的结果
E1 = 0 #上一次的计算结果
time = 0 #循环次数
m = len(x) #点的数量
k = 0 #k的初值,可以自己设为其他的数

while True:
    time += 1
    for i in range(m):
        err = k * x[i] - y[i]
        k -= a * err * x[i] / m #令k增大/减小

    for j in range(len(x)):
        E +=(y[j] - k*x[j])**2/2/m #计算E

    if abs(E - E1) < error: #当两次E的差值在我们允许的范围内时,退出循环
        break #结束循环,while True语句一定要有结束循环的条件,否则会一直循环下去。

    else:
        print('k:%f err:%f'%(k,E))
        E1 = E
        E = 0 #将E重置

print('Over,k=%f'%(k))
print('%dtimes'%(time))

运行结果:
在这里插入图片描述

y = kx + b

y=kx只是众多情况中较为简单的一种,实际的一元线性方程中往往都是有“b”的。
不过,即使增加了一个参数,也没有影响,我们依然可以用同样的原理来完成梯度下降。

梯度下降

如今E的计算公式又增加了一个参数b,那么我们就要分别对k和b进行梯度下降,同样通过求偏导数的方法来实现:
在这里插入图片描述
然后k和b分别减去偏导数:
在这里插入图片描述
同样可以实现梯度下降
因为现在是由两个参数共同决定E的值,所以图像也从二维升到了三维,不过梯度下降的原理并不会改变

代码实现

x = [1,2,3,4,5]#自定义ABCDE的横座标
y = [102,103,104,105,106]#自定义ABCDE的纵座标

error = 0.00001 #我们允许的 两次E的差的范围
a = 0.01 #学习率
err = 0 #初始化 f(xi)-yi 的值
E = 0 #前文计算性能度量的结果
E1 = 0 #上一次的计算结果
time = 0 #循环次数
m = len(x) #点的数量
k = 0 #k的初值,可以自己设为其他的数
b = 0 #b的初值,可以自己设为其他的数

while True:
    time += 1
    for i in range(m):
        err = k * x[i] + b - y[i]
        k -= a * err * x[i] / m #令k增大/减小
        b -= a * err / m #令b增大/减小

    for j in range(len(x)):
        E +=(y[j] - k*x[j] - b)**2/2/m #计算E

    if abs(E - E1) < error: #判断E值是否符合我们的要求
        break #结束循环,while True语句一定要有结束循环的条件,否则会一直循环下去。

    else:
        print('k:%f b:%f err:%f'%(k,b,E))
        E1 = E
        E = 0 #将E重置

print('Over,k=%f,b=%f'%(k,b))
print('%dtimes'%(time))

运行结果:
在这里插入图片描述
如此,一元线性回归的批量梯度下降法(BGD)便完成了,除了BGD,还有随机梯度下降、小批量梯度下降等,这些可能会在以后单独再写。

在线性回归中,梯度下降是比较常用的方法,此外还有最小二乘法等。这会在之后的几期中详细说明,并将二者进行对比。


我是康.,希望做一名能帮助到各位的博主!机器学习系列刚刚开坑,请多指教!
除了机器学习,我偶尔还会做一些单片机/嵌入式、Python相关的文章,欢迎感兴趣的小伙伴与我共同学习,一起进步!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章