机器学习—02线性回归

爱⌒轻易说出口 提交于 2020-01-28 18:25:20

一、单变量线性回归

最简单的开始:线性方程
在这里插入图片描述
简单来说:
线性:穿过很多点的直线,利用这个算法生成的模型一定是一条直线
回归:求解方程的步骤,让数据回归(聚集)到一个特定的模型中,如果特定的模型指的是线性,那么就是让所有点都靠近这条线

线性回归实例:

房屋面积(x) 房屋总价(y)
40 78
96 200
135 330

在这里插入图片描述

m:训练集数据的总量
x:输入变量
y:输出变量,也叫做标签
(x,y):一个训练样本
( xi , yi ):第i个训练样本

属于有监督的学习:可以预测到一个确定的结果

我们知道机器学习的基本步骤是:
在这里插入图片描述
对于一元线性回归(单变量线性回归)来说,学习算法的模型公式为: y = ax + b
(a:斜率 b:截距)
我们换一种写法:hθ(x) = θ0 + θ1x1
线性回归实际上要做的事是:选择合适的参数(θ0,θ1),使得模型hθ(x)能很好的拟合我们的数据

在这里插入图片描述
如图,图3才是最接近训练集的拟合,因此也就是要求出这条直线的系数θ0,θ1

用法:

  • 导包:
    from sklearn.linear_model import LinearRegression
  • 导数据:把数据x 和y 准备好
  • 建模:
    实例化一个线性回归类
    lin_reg = LinearRegression()
    通过fit()方法训练模型得到hθ(x)
    lin_reg.fit(x,y)
    建模完成后,模型的参数就已经存到了lin_reg里,可以通过 lin_reg.intercept_lin_reg.coef_ 查看系数
  • 进行预测
    把需要做预测的输入数据x_predict准备好,进行预测
    lin_reg.predict(x_predict)

练习:利用Sklearn做线性回归的预测

import numpy as np
from sklearn.linear_model import LinearRegression

#准备好数据 x ,y
X = 2 * np.random.rand(100, 1) #生成100行1列的0~2的均匀分布的数
y = 4 + 3 * X + np.random.randn(100, 1) # 加了误差,100行1列,服从正态分布

lin_reg = LinearRegression() # 实例化对象

# 训练模型:fit()方法
lin_reg.fit(X, y)

# intercept 是截距 coef是参数
print(lin_reg.intercept_, lin_reg.coef_)

# 预测
X_new = np.array([[0], [2]]) #x的值必须是2维数组
print(lin_reg.predict(X_new))

运行结果:
在这里插入图片描述

"""
[3, 5, 7, 9, 11, 13, 15, 17, 19, 21, ?]
求第11个数
"""

import numpy as np
from sklearn.linear_model import LinearRegression

x = np.array([1,2,3,4,5,6,7,8,9,10]).reshape(-1,1) # x是二维数组
y = np.array([3,5,7,9,11,13,15,17,19,21])

lin_reg = LinearRegression()      # 实例化对象 
lin_reg.fit(x,y)                  # 进行学习
print(lin_reg.predict([[11]]))    # 预测第11个值,二维数组
print(lin_reg.intercept_, lin_reg.coef_) # 斜率和截距

运行结果:
在这里插入图片描述
numpy模块:用来存储和处理大型矩阵,用于数组计算

import numpy as np

#创建一维数组:
arr = np.arrary([1,2,3])
#创建二维数组:
arr = np.array([1,2,3],[4,5,6])
#查看维度:
arr.ndim
#查看尺寸:n行m列
arr.shape
#查看元素总数:
arr.size
#生成10行1列的0~1的一维数组:
np.random.random(10,1)
#生成10行1列的0~1的一维数组,数符合正态分布
np.random.randn(10,1)
#生成10行1列的0~1的一维数组,数符合均匀分布
np.random.rand(10,1)
#生成指定范围内的整数
np.random.randint(1,5,size=[3,4])

注意:
预测时,x的值必须是二维数组[[ ]]
可以通过 reshape(m, n) 转换

#将数组[1,2,3]转换成1行1列的二维数组
x = np.array([1,2,3]).reshape(-1,1) 

二、损失(代价)函数——均方误差

1、损失函数J(θ0,θ1)

那么怎么来判断我们所得的模型是不是最优的拟合呢,就要用到损失函数。
损失函数:是测量所有的点与模型(一条直线)距离的平均和的一个公式。如果这个距离为0,也就是说所有的点都在这条直线上,那么这时候就是最优解,如果没有达到这个条件,我们就希望这个距离(损失函数)尽可能的小,越小,越靠近最优解。
在这里插入图片描述
预测值: f(xi) ,我们写为 hθ(x)
真实值:yi
一个点的损失值:
在这里插入图片描述
所有点的损失:
在这里插入图片描述
再求平均,除以2方便后面计算,得到损失函数为:
在这里插入图片描述

hθ(x) 与J(θ0,θ1)的关系:
hθ(x)是一个关于x的函数
设有hθ(x) = θ1x1
θ0 = 0 ,θ1 分别等于 0.5 , 1 , 1.5
与真实值 y = x 进行比较时
在这里插入图片描述
在这里插入图片描述

当θ1=0.5时,J =( (1-0.5) ^2 + (2 - 1)^2 + (3 - 1.5)^2) / 6 = 0.583
当θ1=1时, J =( (1-1) ^2 + (2 - 2)^2 + (3 - 3)^2) / 6 = 0
当θ1=1.5时,J =( (1- 1.5) ^2 + (2 - 3)^2 + (3 - 4.5)^2) / 6 = 0.583
可以得到J(θ0,θ1)函数
J(θ0,θ1)是一个关于θ1的函数
在这里插入图片描述

3、损失函数的等高图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到,当直线拟合的越好,等高图中越接近中心点

三、梯度下降

1、梯度下降思想

在数学中的梯度下降是:
xk+1 = xk + λkPk
λk表示步长
Pk表示方向
沿着方向不断更新x,直到x达到最小

为了得到最好的拟合线,我们的目标是让损失函数达到最小
因此,引入梯度下降的思想:
条件:有一个J(θ0,θ1)
目标:让J(θ0,θ1)最小
步骤:
1、初始化θ0,θ1
2、持续改变θ0,θ1的值,让J(θ0,θ1)越来越小
3、直到得到一个J(θ0,θ1)的最小值

2、梯度下降算法

重复执行:
在这里插入图片描述
其中:α为学习率,也是步长
在这里插入图片描述

不论斜率正或负,梯度下降都会逐渐趋向最小值
如果α太小的话,梯度下降会很慢
如果α太大的话,梯度下降会越过最小值,不仅不会收敛,还有可能发散
即使α是固定不变的,梯度下降也会逐渐到一个最低点,因为随着梯度下降迭代次数的递增,斜率会趋于平缓,也就是说,倒数部分会慢慢变小

3、线性回归的梯度下降

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、三种梯度下降

1、批梯度下降

批梯度下降Bath Gradient Descent:
指每下降一步,使用所有的训练集来计算梯度值

import numpy as np

X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
X_b = np.c_[np.ones((100, 1)), X]
# print(X_b)

#学习率α
learning_rate = 0.1
# 通常在做机器学习的时候,一般不会等到它收敛,太浪费时间,所以会设置一个收敛次数n_iterations
n_iterations = 1000
#样本数
m = 100

# 1.初始化 θ0 , θ1
theta = np.random.randn(2, 1)
count = 0

# 4. 不会设置阈值,之间设置超参数,迭代次数,迭代次数到了,我们就认为收敛了
for iteration in range(n_iterations):
    count += 1
    # 2. 接着求梯度gradient
    gradients = 1.0/m * X_b.T.dot(X_b.dot(theta)-y)
    # 3. 应用公式不断更新theta值
    theta = theta - learning_rate * gradients
print(count)
print(theta)

运行结果:
在这里插入图片描述
这里其实我还是想拿矩阵来解释一下
函数 hθ(x) = -4000 + 12000x
当x = 120 , 150 时,方程可由矩阵表示为
在这里插入图片描述
代码中:
np.c_[ ] 表示把2个维度相同的矩阵拼在一起
np.ones((100,1)) 表示100行1列元素全是1的矩阵
np.dot(a,b) 表示矩阵a和b点乘,或者写为 a.dot(b)
.T 表示求矩阵的转置

计算梯度的这段代码: gradients = 1.0/m * X_b.T.dot(X_b.dot(theta)-y)

为了方便起见,就以2个样本数量x1,x2 来解释吧
在这里插入图片描述

在这里插入图片描述

再除以m : 1.0/m * X_b.T.dot(X_b.dot(theta)-y) ,就相当于红框中的这一部分
在这里插入图片描述
因此:不断更新的theta值就为:
theta = theta - learning_rate * gradients

2、随机梯度下降

随机梯度下降Stochastic Gradient Descent
指的是每下降一步,使用一条训练集来计算梯度值
把m个样本分成m份,每次用1份做梯度下降;也就是说,当有m个样本时,批梯度下降只能做一次梯度下降,但是随机梯度下降可以做m次

有一个概念:epoch 轮次
1 epoch = 1次遍历所有的数据
对于批梯度下降来说,1次梯度下降就是1epoch
对于随机梯度下降来说,需要做m次才是1epoch

import numpy as np
import random

x = 2 * np.random.rand(100, 1)
y = 4 + 3 * x + np.random.randn(100 ,1)
X = np.c_[np.ones((100, 1)), x]

n_epochs = 500         # 轮次
learning_rate = 0.1    # 学习率
m = 100                # 样本数
num = [i for i in range(m)]    # 列表num:0 ~ 99
theta = np.random.rand(2, 1)     # 初始化theta值

#  做500epoch,一次处理1条,一个epoch循环100次
for epoch in range(n_epochs):
    rand = random.sample(num, m)   # 在列表num中随机选取100个数字,其实是将顺序打乱
    #print(rand)
    for i in range(m):
        random_index = rand[i]   # rand是一个列表,拿到列表中的每一个元素作为索引
        xi = X[random_index: random_index+1]    # 随机选取一个样本
        yi = y[random_index: random_index+1]
        gradients = xi.T.dot(xi.dot(theta) - yi)  #只选取了1个样本,所以乘以的是 1/1
        theta = theta - learning_rate * gradients

print(theta)

运行结果:
在这里插入图片描述

3、Mini-Batch梯度下降

Mini-Batch Gradient Descent
指的是每下降一步,使用一部分的训练集来计算梯度值

如果mini-batch 大小 = m:它就是批梯度下降
如果mini-batch 大小 = 1 :它就是随机梯度下降
如果 1 < mini-batch大小 < m :它就是Mini-Batch梯度下降

import numpy as np
import random

x = 2 * np.random.rand(100, 1)
y = 4 + 3 * x + np.random.randn(100 ,1)
X = np.c_[np.ones((100, 1)), x]

n_epochs = 500         # 轮次
learning_rate = 0.1    # 学习率
m = 100                # 样本数
theta = np.random.rand(2, 1)  # 初始化theta值

batch_num = 5             # 循环5次
batch_size = m // 5       # 一次处理20条

# 做500epoch, 一次处理20条,一个epoch循环5次
for epoch in range(n_epochs):
    for i in range(batch_num):  # 循环5次
        start = i * batch_size
        end = (i + 1) * batch_size
        xi = X[start: end]
        yi = y[start: end]
        gradients = 1 / batch_size * xi.T.dot(xi.dot(theta) - yi) #选取了batch_size个样本,所以乘以 1/batch_size
        theta = theta - learning_rate * gradients

print(theta)

运行结果:
在这里插入图片描述

4、三种梯度下降比较

梯度下降类别 速度 准确度
批梯度下降 最慢 最准确
Mini-Batch梯度下降 中等 中等
随机梯度下降 最快 不准确

如何选择:
随机梯度下降会丧失向量带来的加速,所以我们不太会用随机梯度下降
当训练集比较小时,使用批梯度下降(小于2000个)
当训练集比较大时,使用Mini-Batch梯度下降
一般的Mini-Batch size为:64,128,256,512,1024
Mini-Batch size要适用CPU/GPU的内存

5、学习率衰减

我们在以上代码中还提到了一个概念 α 学习率
一般我们选择α时,可以尝试 :1,0.1,0.2,0.3…
在做Mini-Batch的时候,因为噪声的原因,可能训练,结果不是收敛的,而是在最低点附近摆动,因为α是固定不变的,如果我们要解决这个问题,就需要减少学习率,让步伐不断减小,让他在尽量小的范围内晃动
因此我们在设置了α初始值后,还可以设置它的衰减率,通过不断更新学习率,从而达到要求

实现方法:
在这里插入图片描述
学习率初始值: a0
衰减率:decay_rate
代数:epoch_num,第几次循环

import numpy as np
import random

x = 2 * np.random.rand(100, 1)
y = 4 + 3 * x + np.random.randn(100 ,1)
X = np.c_[np.ones((100, 1)), x]

a0 = 0.1               # 学习率初始值
decay_rate = 1         # 衰减率
#  更新学习率
def learning_schedule(epoch_num):
    return (1.0 / (1 + decay_rate * epoch_num )) * a0

n_epochs = 500         # 轮次
m = 100                # 样本数
theta = np.random.rand(2, 1)  # 初始化theta值

batch_num = 5             # 循环5次
batch_size = m // 5       # 一次处理20条

# 做500epoch, 一次处理20条,一个epoch循环5次
for epoch in range(n_epochs):
    for i in range(batch_num):  # 循环5次
        start = i * batch_size
        end = (i + 1) * batch_size
        xi = X[start: end]
        yi = y[start: end]
        gradients = (1 / batch_size) * xi.T.dot(xi.dot(theta) - yi)
        learning_rate = learning_schedule(i) # 更新的学习率
        theta = theta - learning_rate * gradients

print(theta)

实现学习率衰减还有其他几种方法:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

五、多变量线性回归

1、多变量线性回归模型

在这里插入图片描述
在这里插入图片描述

2、多元梯度下降

在这里插入图片描述

import numpy as np
import random

from sklearn.linear_model import LinearRegression
x1=np.array([1,1,1])
x2=np.array([1,1,2])
x3=np.array([2,2,2])
x4=np.array([1,2,3])
x5=np.array([2,3,4])
x=np.c_[x1,x2,x3,x4,x5]
y=np.array([3,4,6,6,9])

lin_reg=LinearRegression()
lin_reg.fit(x.T,y)

print(lin_reg.intercept_,lin_reg.coef_)

x_new=np.array([[12,15,17]])
print(lin_reg.predict(x_new))
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!