最近因项目需要,学习了一个多月的机器学习算法,从基础理论到sklearn,再到tensorflow 2.0教程都看了一个遍,似乎有点感觉了,现在基本上可以通过调包实现大多数的常见算法以及常见调参调优方法。
今天突发奇想,想自己用python原生代码写一个最简单的线性回归梯度下降算法来检验一下自己学得是否扎实。
不写不知道,一写吓一跳,本来觉得自己公式啥的都可以手推了,结果写起来还是问题一大堆,比如:以前从没考虑过收敛,结果第一遍代码写完误差却越来越高,一查原因原来是收敛条件没加限制,本来想用线性代数实现,结果研究传参的数据结构整了半个多小时,本来将步长设为0.01时,发现效果并不好。
好了,废话不多说了,直接上代码:
import matplotlib.pyplot as plt
import math
class Linear:
def __init__(self):
# 数据集,self.x为横轴,self.y为纵轴
self.x = [x for x in range(1,11)]
self.y = [2,6,8,9,11,15,21,25,30,35]
def predict(self):
# 设线性模型 y = kx + b,以下是对k,b两个参数的初始化
k = 0.0
b = 0.0
# alpha为步长,最好搞小点,刚开始我设的0.01,效果不好
alpha = 0.0001
# errors 为每次的MSE数值
errors = []
c = 0
while True:
# delta_k 为参数k的偏导
delta_k = 0.0
# delta_b 为参数b的偏导
delta_b = 0.0
mse = 0.0
for i in range(len(self.x)):
delta_k += (k * self.x[i] + b - self.y[i]) * self.x[i]
delta_b += k * self.x[i] + b - self.y[i]
mse += 0.5 * math.sqrt((k * self.x[i]+b - self.y[i])**2)
k = k - alpha * delta_k
b = b - alpha * delta_b
print(k,b)
print(mse)
errors.append(mse)
# 控制收敛逻辑,当本次MSE值减去上次MES值小于0.2时,退出收敛
if len(errors)>1 and (errors[c-1]-errors[c])<0.2:
break
c += 1
# 下面这句是画出MSE的收敛曲线
# plt.scatter([x for x in range(100)],errors)
# 下面是画出原数据集散点图
plt.scatter(self.x,self.y)
# 下面根据得出的k,b的值,画出得到的直线
plt.plot(self.x,[k*x+b for x in self.x])
plt.show()
if __name__ == '__main__':
line = Linear()
line.predict()