一、准备数据
生成N个训练样本(X,Y),其中自变量X取值服从均值为0,方差为1 的正太分布.
设该线性方程的式子为:Y = w*X + b.
以下我们以Y =3*X+7 + e_r, N=100为例.
Y =3*X+7 + e_r, 其中 e_r为误差项,其取值服从均值为0,方差为1 的正太分布.
创建数据后查看数据散点图,代码及数据散点图如下:
import numpy as np
import matplotlib.pyplot as plt
a = 0
b = 1
num = 100
#创建样本,均值a=0,方差b=1,数量num为100
x = np.random.normal(a, b, num)
e_r = np.random.normal(a, b, num)
y =3*x+7 + e_r
plt.scatter(x, y)
plt.show()
二、定义一个LinearModal 类,实现梯度下降,数据预测等。
先来理解一些基础概念。Y= w*X+b,w代表权重,b代表偏置值。我们的目的就是要求出合适的w和b,用Y= w*X+b这条曲线来拟合我们的数据集。
2.1 那么如何求w和b呢
用梯度下降法
梯度下降的通俗理解就是:我们可以先给未知量w和b一个初始值。然后通过让它们自己学习一直变,变到合适的值为止。
以我们的例子为例,最终结果应当是Y =3*X+7这条曲线拟合数据集的。我们假设w=1,b=1.进行一次梯度下降后,可能w就变成2,b就变成3(此处夸大了,一般变化不会那么大,一般变化很小,所以需要梯度下降很多次).就这样子一直变化直到w和b合适为止。
2.2 那么如何判断是否已经合适了呢
用损失函数
用均方差作为我们的损失函数,当误差值处于可接受范围时,则说明已找到合适的w和b,公式如下所示:
y代表预测值,即式子y=w*x+b得到的值,Y代表真实值
由公式可知loss函数是一条关于y的二次函数,为开口向上的抛物线
2.3 那么如何确定未知量的变化梯度呢
由高中数学我们就知道,导数可以说是x对y的影响程度,如y=7x,导数为7,而如y=2x,导数为2,很明显,当x变化同等程度时,第一条函数的y值变化更大。
所以我们要求出w和b的变化梯度就是求导,求它们的偏导。偏导代表他们对loss值的影响程度。求偏导公式如下(因为公式编辑太麻烦,直接手写,字丑见谅):
Tips:公式推导很简单,看一下能看懂的。
求出偏导后,w和b的变化公式就是:
kw,kb分别代表w和b的偏导
至于为什么要用减法,简单想想,当偏导值为负数时,则证明此时位于loss函数的左侧,需要增大变量值来趋近极值点。反之同理。如下粗略图,横轴为y,纵轴为loss:
由上总结出提纲
- 数据准备
- 定义LinearModal类
- 初始化w,b为1
- 求loss
- 求偏导
- 更新w和b
- 回到第二点一直循环遍历直至迭代次数完成或loss达到可接受范围
- 实例化LinearModal类并进行预测
- 绘图
理解思路后,定义LinearModal类:
class LinearModal():
def __init__(self, x, y, m, LearningRate):
self.w = 1 #初始化w
self.b = 1 #初始化b
self.LearningRate = LearningRate
self.x = x
self.y = y
self.kb = 0 #b的偏导
self.kw = 0 #w的偏导
self.m = m #训练次数
#进行一次梯度下降
def gradentdecent(self):
# 求样本数量
n = len(self.x)
loss = 0
#求和
for j in range(n):
# kw = 求和 (wx+b-y)*x
# kb = 求和 (wx+b-y)
# loss = 求和 (wx+b-y)²
self.kw = self.kw + ((self.w*self.x[j]+self.b-self.y[j])*x[j])
self.kb = self.kb + (self.w*self.x[j]+self.b-self.y[j])
loss = loss + (self.w*self.x[j]+self.b-self.y[j])**2
self.kw = self.kw*2/n
self.kb = self.kb*2/n
loss = loss/n
return self.kw,self.kb,loss
#训练函数
def train(self):
#循环训练次数
for i in range(self.m):
#训练一次
self.kw, self.kb, loss = self.gradentdecent()
# 如果误差值已达可接受范围则退出循环
if loss <= 0.0001:
break
#更新w和b
# w = w - kw * LearningRate
# b = b - kb * LearningRate
self.w = self.w - self.kw*self.LearningRate
self.b = self.b - self.kb*self.LearningRate
#预测
def predict(self):
y_predict = self.w*self.x+self.b
return y_predict
三、预测
#创建模型
lm = LinearModal(x, y, 10000, 0.001)
#开始训练
lm.train()
#获取训练到的相关预测数据
w_predict = lm.w
b_predict = lm.b
y_predict = lm.predict()
print('预测到的w为{},预测到的b为{}'.format(w_predict,b_predict))
#绘图
plt.scatter(x, y)
plt.plot(x, y_predict, color='red')
plt.show()
由输出结果可知,w趋近3,b趋近7,证明拟合效果极佳。
自此一元线性回归梯度下降法完成,如有错误还请指教