线性回归模型

线性回归是一种找到适合训练模型的拟合曲线的一种算法,对于一般的数据,我们通常会选择y=w1x+w0这个数学公式去拟合训练出对应的曲线。

但是这归根到底也只是一个直线,对于分布不均的散点图来说,不可能直接算出确定的w1w0,这就需要我们不断地通过训练,循环,通过梯度下降等算法来求得最为接近于所求数据的拟合直线

1.用3d图像显示w0,w1,loss关系

from mpl_toolkits.mplot3d import axes3d
%matplotlib notebook
xs=np.array([0.5,0.6,0.8,1.1,1.4])
ys=np.array([5.0,5.5,6.0,6.8,7.0])
n=500
loss=0
w0_grid,w1_grid=np.meshgrid(np.linspace(-10,10,n),np.linspace(-10,10,n))
for x,y in zip(xs,ys):
    loss+=(w0_grid+w1_grid*x-y)**2/2
plt.figure('Loss Function',facecolor='lightgrey')
ax3d=plt.gca(projection='3d')
ax3d.set_xlabel('w0')
ax3d.set_ylabel('w1')
ax3d.set_zlabel('loss')
ax3d.plot_surface(w0_grid,w1_grid,loss,cstride=30,
                  rstride=30,cmap='jet')
plt.show()
plt.tight_layout()

我们可以随便取一个训练数据xs,ys,这是我们所要去拟合的数据关系。

接着我们需要理解的是loss的含义,loss相当于就是我们(预测数据-实际数据)的平方除以二,但其实后面的平方除以二并不是那么重要,是为了之后在求导的时候可以直接约掉而已,关键要理解的就是预测数据-实际数据,这就是我们所要求的每次训练的差值。

随着不断地训练,w0,w1不断改变然后就会趋近于一个我们所要求的曲线最低点的数值,就跟二次函数那样,我们要求的就是loss最小极值情况下w0,w1,不过一般我们不可能算的那么精确,控制训练次数后大概误差在小数点后4位以上也就差不多结束了。

如果这样我们还是不能理解梯度下降这样的趋势的话,我们可以加入其下降的曲线于3d图像中,这里我把学习率调到的稍微高了些,方便能直接观看

import mpl_toolkits.mplot3d as axes3d
%matplotlib notebook
n=500
train_x = np.array([0.5, 0.6, 0.8, 1.1, 1.4])
train_y = np.array([5.0, 5.5, 6.0, 6.8, 7.0])
times = 1000    # 定义梯度下降次数
lrate = 0.2    # 记录每次梯度下降参数变化率
epoches = []    # 记录每次梯度下降的索引
w0, w1, losses = [1], [1], []
for i in range(1, times + 1):
    epoches.append(i)
    loss = (((w0[-1] + w1[-1] * train_x) - train_y) ** 2).sum() / 2
    losses.append(loss)
    d0 = ((w0[-1] + w1[-1] * train_x) - train_y).sum()
    d1 = (((w0[-1] + w1[-1] * train_x) - train_y) * train_x).sum()
    
    w0.append(w0[-1] - lrate * d0)
    w1.append(w1[-1] - lrate * d1)
print('w0:',w0[-1])
print('w1:',w1[-1])
grid_w0, grid_w1 = np.meshgrid(
    np.linspace(0, 9, n),
    np.linspace(0,3.5 , n))

grid_loss = 0
for x, y in zip(train_x, train_y):
    grid_loss += ((grid_w0 + x*grid_w1 - y) ** 2) / 2

mp.figure('Loss Function')
ax = mp.gca(projection='3d')
mp.title('Loss Function', fontsize=20)
ax.set_xlabel('w0', fontsize=14)
ax.set_ylabel('w1', fontsize=14)
ax.set_zlabel('loss', fontsize=14)
ax.plot_surface(grid_w0, grid_w1, grid_loss, rstride=10, cstride=10, cmap='jet')
ax.plot(w0[:-1], w1[:-1], losses, 'o-', c='orangered', label='BGD')
mp.tight_layout()
mp.legend()

我们能看到这里橙色曲线就是我们不断更新的w0,w1以及loss的曲线,当学习率较高的时候,其改变斜率的幅度也会变大(不过要当心不能过大,否则趋势就不是梯度下降而是梯度上升)因此我们可以根据图像来继续调整我们的学习率,来得到更为恰当的w0,w1。

2.用曲线表示w0,w1,以及回归线

我们所能做的最简单的回归方法,就是对训练数据进行偏导求差,然后得到一定差值后就可以分别对w0,w1梯度下降

train_x = np.array([0.5, 0.6, 0.8, 1.1, 1.4])
train_y = np.array([5.0, 5.5, 6.0, 6.8, 7.0])

times = 1000
w0, w1 = 1, 1
lrate = 0.01
for i in range(times):
    # 求得w0方向上的偏导数用于更新w0
    d0 = (w0 + w1*train_x - train_y).sum()
    # 求得w1方向上的偏导数用于更新w1
    d1 = (train_x*(w0 + w1*train_x - train_y)).sum()
    # 更新w0与w1
    w0 = w0 - d0*lrate
    w1 = w1 - d1*lrate
print('w0:', w0, '  w1:', w1)
# 画图
plt.figure('Linear Regression', facecolor='lightgray')
plt.title('Linear Regression', fontsize=18)
plt.grid(linestyle=':')
plt.scatter(train_x, train_y, color='dodgerblue',
    s=80, marker='o', label='Samples')
# 绘制回归线
pred_train_y = w0 + w1*train_x
plt.plot(train_x, pred_train_y, color='orangered',
    label='Regression Line', linewidth=2)
plt.legend()
plt.show()

这里的d0,d1的求法就是运用到了偏导数的求法,同时我们也看到了之前对loss进行平方除以2的好处就在于其导数直接可以约掉这些数值,只留下里面的w0,w1,以及训练数据变量。

每次循环就会更新一次w0,w1,通过图像我们能更直观的看出来对于一般的散点图来说拟合直线与原数据的loss确实是比较小的。

3.用等高线图表示梯度下降

mp.figure('Batch Gradient Descent', facecolor='lightgray')
mp.title('Batch Gradient Descent', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.grid(linestyle=':')
mp.contourf(grid_w0, grid_w1, grid_loss, 10, cmap='jet')
cntr = mp.contour(grid_w0, grid_w1, grid_loss, 10,
                  colors='black', linewidths=0.5)
mp.clabel(cntr, inline_spacing=0.1, fmt='%.2f',
          fontsize=8)
mp.plot(w0, w1, 'o-', c='orangered', label='BGD')
mp.legend()
mp.show()

等高线图相信大家在此之前都差不多学过,我就不多加赘述。

这张图中我们所要观察的就是BGD曲线,它所代表的就是w0,w1从1开始然后不断的向低处走,我们可以看到在y为3即w1为3的时候曲线折向发展,就是因为在中间这块区域的深度也不是一样的,最终曲线会找到这整个等高线中最低点的位置即我们所要训练得到的最小loss,这就是我们所要理解的梯度下降的意义。

4.线性回归API

大家在前面的学习肯定会觉得每次都要输入一次计算更新数据的算法比较麻烦,因此我在这里引出sklearn.linear_model这个包,

导入包后我们所要做的就是先创建模型

# 创建模型
model = lm.LinearRegression()  # 线性回归

之后就是将训练数据导入模型之中梯度下降进行运算

# 训练模型
model.fit(x, y)

之后我们想要知道这个曲线的拟合情况的话,就可以直接把原本的x导入看看所形成的y是如何

# 根据输入预测输出
pred_y = model.predict(x)

这就是这个包的简单用法了,比之前的运算方便了许多

import numpy as np
import sklearn.linear_model as lm
import matplotlib.pyplot as mp
# 采集数据
x, y = np.loadtxt('single.txt', delimiter=',', usecols=(0,1), unpack=True)
x = x.reshape(-1, 1)
# 创建模型
model = lm.LinearRegression()  # 线性回归
# 训练模型
model.fit(x, y)
# 根据输入预测输出
pred_y = model.predict(x)
mp.figure('Linear Regression', facecolor='lightgray')
mp.title('Linear Regression', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.grid(linestyle=':')
mp.scatter(x, y, c='dodgerblue', alpha=0.75, s=60, label='Sample')
mp.plot(x, pred_y, c='orangered', label='Regression')
mp.legend()
mp.show()

我们可以看到这个拟合效果还是不错的

但是我们这里不像之前可以直接查阅loss啊这些数值了,就不能直接了解拟合数据是否多精确

所以在这里我们可以引出另外一个包,也是sklearn里的

import sklearn.metrics as sm

# 平均绝对值误差:1/m∑|实际输出-预测输出|
sm.mean_absolute_error(y, pred_y)
# 平均平方误差:SQRT(1/mΣ(实际输出-预测输出)^2)
sm.mean_squared_error(y, pred_y)
# 中位绝对值误差:MEDIAN(|实际输出-预测输出|)
sm.median_absolute_error(y, pred_y)
# R2得分,(0,1]区间的分值。分数越高,误差越小。
sm.r2_score(y, pred_y)

前三个方法我们能算出其大概的误差,大抵是求得绝对值的实际-预测后进行求和后再处于个数或者直接求得其中的中位数这样,求得的数据基本类似。

而最后一个方法就相当于给这个模型计算一下它的算法成功率,计算他的分数,我们可以看到这里大概是0.73,可以理解为73分,大概合格的水准,如果想要分数更高,就需要其他的线性模型方法了。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值