一、 环境:
- 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()