文章目录
一、单变量线性回归
最简单的开始:线性方程
简单来说:
线性:穿过很多点的直线,利用这个算法生成的模型一定是一条直线
回归:求解方程的步骤,让数据回归(聚集)到一个特定的模型中,如果特定的模型指的是线性,那么就是让所有点都靠近这条线
线性回归实例:
房屋面积(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))
来源:CSDN
作者:小黑--
链接:https://blog.csdn.net/qq_41645466/article/details/104091220