Python梯度下降法实现单变量线性回归算法实现(学习笔记)

一、      环境:

  • Python 3.7.4
  • Pycharm Community 2019.3

二、      问题:

     针对舰船长宽之比的数据,编写一个拟合程序,计算出拟合参数,并画出相应的数据散点图及拟合直线。

编号

长度 (m)

宽度 (m)

i

 ti

 yi

1

208

21.6

2

152

15.5

3

113

10.4

4

227

31

5

137

13

6

238

32.4

7

178

19

8

104

10.4

9

191

19

10

130

11.8

 

三、      理论推导

  • Model:Y=aX+b+ε(此处a为斜率,b为截距,ε为误差)
  • 根据给定的一组样本值(yi,xi)来估计误差最小的a和b,通常采用最小二乘法,其计算目标为最小化残差平方和:
  • 即求上方损失量最小值将上式分别对α和β求一阶偏导(用Ta和Tb来表示):

 

  • 根据梯度的定义,梯度方向是增大的方向,所以我们可以知道梯度的反方向减小的方向,所以我们便可以通过不断去求偏导并不断去调整 a和 b来得到的最小值,现在我们来考虑俩个问题:

1.对a和b的调整幅度是多少?

此处我们引入学习率rate来控制 a,b 的调整幅度

 

调整时我们用a减去Ta*rate,b同理

学习率的选择很重要,不能过大也不能过小

当学习率过大时会很难捕捉到最低点(如左图),而当学习率过小时可能会把局部最优解作为结果,而得不到真正的最优解(如右图)

 

2.如何来判断找到了我们想要的结果?

此处引入精确度acc

我们可以来比较调整前a和调整后a’的大小

当|a-a’|<acc时认为找到了合适的a

b与a同理

我们还需要设置一个count值来确保程序能停止计算

  • 现在我们来整理下流程

首先我们有n组数据(Xi,Yi),

初始化学习率rate、精确度acc、循环上限count、a、b、last_a、last_b

进行循环计算

{

       比较last_a、last_b和a、b的值,若差值都小于acc,跳出循环

       比较cyc_count和count,若cyc_count<count,跳出循环

       计算得出Ta和Tb     

}

此时a和b就是最终结果

四、      代码实现

 1 import numpy as np
 2 import matplotlib.pyplot as plt
 3 
 4 
 5 class LineerModel(object):
 6     def __init__(self, a, b, count, rate, acc, x, y):
 7         self.a = a
 8         self.b = b
 9         self.count = count
10         self.rate = rate
11         self.acc = acc
12         self.x = x
13         self.y = y
14         self.last_a = a
15         self.last_b = b
16 
17     def model(self, x):
18         return self.a * x + self.b
19 
20     def update(self, gradient_a, gradient_b, learning_rate=0.0001):
21         self.last_a = self.a
22         self.last_b = self.b
23         self.a -= gradient_a * learning_rate
24         self.b -= gradient_b * learning_rate
25 
26     def fit(self):
27         self.last_a = self.a + 100
28         self.last_b = self.b + 100
29         count = 0
30         length = self.x.__len__()
31         while True:
32             if count > self.count:
33                 break
34             if (abs(self.a - self.last_a) < self.acc) and (abs(self.b - self.last_b) < self.acc):
35                 break
36             cost = 0
37             gradient_a = 0
38             gradient_b = 0
39             for i in range(length):
40                 cost += ((self.y[i] - self.model(self.x[i])) ** 2) / length
41                 gradient_a -= (self.x[i]*(self.y[i] - self.model(self.x[i]))) / length
42                 gradient_b -= (self.y[i] - self.model(self.x[i])) / length
43             print(f'执行次数:{count},损失量:{cost},a精确度:{abs(self.a - self.last_a)},b精确度:{abs(self.b - self.last_b)}')
44             self.last_a = self.a
45             self.last_b = self.b
46             self.update(gradient_a, gradient_b, 0.001)
47             count += 1
48 
49     def result(self):
50         return self.a, self.b
51 
52 
53 x = np.array([21.6, 15.5, 10.4, 31, 13, 32.4, 19, 10.4, 19, 11.8])
54 y = np.array([208, 152, 113, 227, 137, 238, 178, 104, 191, 130])
55 lm = LineerModel(5, 60, 300, 0.0001, 0.001, x, y)
56 lm.fit()
57 a, b = lm.result()
58 plt.scatter(x, y, c='red')
59 plt.plot(x, a * x + b, color='green')
60 print(a,b)
61 plt.show()

猜你喜欢

转载自www.cnblogs.com/FSeng/p/12187027.html
今日推荐