首页 > 其他分享 >线性回归模型的构建与训练

线性回归模型的构建与训练

时间:2025-01-02 23:00:51浏览次数:3  
标签:plt 迭代 梯度 模型 random np 构建 线性 theta

1.基本的导入与配置

# To support both python 2 and python 3
from __future__ import division, print_function, unicode_literals

# Common imports
import numpy as np
import pandas as pd
import os

# to make this notebook's output stable across runs
np.random.seed(42)

# To plot pretty figures
%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rc('axes', labelsize=14)
mpl.rc('xtick', labelsize=12)
mpl.rc('ytick', labelsize=12)

# Where to save the figures
PROJECT_ROOT_DIR = "."
CHAPTER_ID = "training_linear_models"

# Ignore useless warnings (see SciPy issue #5998)
import warnings
warnings.filterwarnings(action="ignore", message="^internal gelsd")

2.正规方程处理线性回归

用y=4+3x+高斯噪声来生成100个数据点(x0为1)

# 首先构造X,维度X中所有点的范围在0-2之间,可利用np.random.rand生成符合均匀分布的0-1之间的点。
X = 2 * np.random.rand(100, 1) 
# 构造y, 可用np.random.randn构造高斯噪声
y = 4 + 3 * X + np.random.randn(100, 1)

用matplotlib查看生成的点

#2
plt.plot(X, y, "b.")
plt.xlabel("$x_1$", fontsize=18)
plt.ylabel("$y$", rotation=0, fontsize=18)
plt.axis([0, 2, 0, 15])
# save_fig("generated_data_plot")
plt.show()

通过求解MSE(均方误差)的最小值^θ=(XT⋅X)−1⋅XT⋅y 求解θ值(这就是一个模型的训练过程)

# add x0 = 1 to each instance
X_b = np.c_[np.ones((100, 1)), X]  
# 通过正规方程求解最佳theta值
theta_best = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y)
theta_best

说明:

X_b = np.c_[np.ones((100, 1)), X]这行代码创建了一个新矩阵X_b,它是原始特征矩阵X的扩展。np.ones((100, 1))生成了一个100行1列的全1矩阵,这在线性代数中常用来表示截距项(也就是当所有特征值为0时的偏置项)。np.c_是NumPy中的一个函数,用于沿着第二轴(列)连接两个数组。所以,X_b实际上是将全1列向量添加到X的每一行前面,以便在模型中包含截距项。

theta_best:

用matplotlib查看拟合的回归函数(的预测结果)

plt.plot(X_new, y_predict, "r-", linewidth=2, label="Predictions")
plt.plot(X, y, "b.")
plt.xlabel("$x_1$", fontsize=18)
plt.ylabel("$y$", rotation=0, fontsize=18)
plt.legend(loc="upper left", fontsize=14)
plt.axis([0, 2, 0, 15])
plt.show()

LinearRegression是基于最小二乘方法的线性模型(训练过程使用正规方程求解)

因此使用LinearRegression求解的theta和y值应该与前面正规方程求出的结果一致。

LinearRegression(

*, # 后面参数都是可选参数

fit_intercept=True, # bool值,指定是否应该计算截距项(即线性方程中的常数项)

copy_X=True, # 指定是否应该复制 X

n_jobs=None, # 指定用于计算的作业数,-1表示使用所有可用的CPU核心,1表示不使用并行计算,None,则作业数由底层实现决定(通常是一个合理的默认值,取决于是否安装了支持并行计算的库,如 joblib

positive=False, # 仅在 fit_intercept=False 时有效,False,则不对系数的符号进行限制,True,则强制系数为正数

)

from sklearn.linear_model import LinearRegression
# Step1:构建LinearRegression()估计器的实例对象lin_reg
lin_reg = LinearRegression()
# Step2:调用实例对象lin_reg的fit方法进行训练
lin_reg.fit(X, y)
# Step2:通过intercept_和coef_查看训练得到的参数值,即线性方程的截断和系数
lin_reg.intercept_, lin_reg.coef_

intercept_属性存储了模型的截距项,coef_属性存储了模型的系数。

说明:

array([4.21509616])这是一个只包含一个元素的数组,表示线性回归模型的截距(intercept)。截距是线性方程中的常数项,也就是当所有特征变量(x值)都为0时,因变量(y值)的预测值。在这个例子中,截距是4.21509616。

array([[2.77011339])这是一个二维数组,包含一个元素的一维数组,表示线性回归模型的系数(coefficients)。系数是线性方程中特征变量的系数,表示每个特征变量对因变量的影响程度。在这个例子中,只有一个特征变量,其系数是2.77011339。

所以,这两个参数定义了一个简单的线性回归方程:

y=4.21509616+2.77011339⋅x

其中,x 是特征变量,y 是因变量。这个方程可以用来预测给定特征变量 x 值的因变量 y 值。

# Step3:调用估计器的predict方法对X_new进行预测
lin_reg.predict(X_new)

第二值是预测的结果y

3.梯度下降训练线性回归

# 学习率
eta = 0.1
n_iterations = 1000

# 有100个数据点 
m = 100

# 随机初始化参数theta,模型有两个参数(包括截距项),因此theta是一个2x1的向量 
theta = np.random.randn(2,1)

for iteration in range(n_iterations):
    # 计算梯度,这里使用了批量梯度下降(BGD)方法  
    # 2/m是归一化因子,确保梯度是平均梯度  
    # X_b.T是扩展特征矩阵的转置,它包含了截距项  
    # X_b.dot(theta) - y计算了模型预测与真实标签之间的误差  
    # 整个表达式计算了损失函数关于theta的梯度  
    gradients = 2/m * X_b.T.dot(X_b.dot(theta) - y)
    # 使用梯度下降法更新参数theta  
    # eta * gradients计算了参数应该更新的量(方向和大小)  
    # theta - eta * gradients则是更新后的参数值  
    theta = theta - eta * gradients

解释:

1.初始化参数:

eta = 0.1:这是学习率,它控制着在每次迭代中参数更新的步长。较小的学习率意味着更新步长较小,可能需要更多的迭代次数来收敛;较大的学习率可能导致更新步长过大,从而越过最优解或导致训练不稳定。

n_iterations = 1000:这是迭代次数,即梯度下降算法将执行1000次迭代。

m = 100:这是数据点的数量,表示训练集中有100个样本。

theta = np.random.randn(2,1):这是参数theta的初始化,theta是一个2x1的向量,包含两个参数(一个是截距项,另一个是特征的系数)。这里使用正态分布随机初始化参数。

2.迭代过程:

for iteration in range(n_iterations):开始1000次迭代的循环。

gradients = 2/m * X_b.T.dot(X_b.dot(theta) - y):计算梯度。

X_b.dot(theta):计算模型预测值,即线性组合X_b(扩展特征矩阵)和theta(参数向量)的点积。

X_b.dot(theta) - y:计算预测值和真实值之间的误差。

X_b.T.dot(...):计算误差与特征矩阵X_b的点积,得到梯度向量。

2/m * ...:将梯度向量除以样本数量m,得到平均梯度,这是批量梯度下降的关键步骤。

theta = theta - eta * gradients:更新参数theta。

eta * gradients:计算参数更新的量,即学习率eta乘以梯度向量gradients。

theta - ...:根据梯度下降的方向更新参数theta,减去计算出的更新量。

3.结果:

经过1000次迭代后,theta将收敛到最小化损失函数的值,即找到了最佳拟合参数。

# 查看梯度下降训练之后的theta
theta

X_new_b.dot(theta)

绘制不同学习率下的学习过程

# 设置随机种子以保证结果的可重复性  
np.random.seed(42)  
# 随机初始化参数theta(模型有两个参数,包括截距项,所以维度为(2,1))  
theta = np.random.randn(2,1)  
  
# 设置绘图的大小  
plt.figure(figsize=(10,4))  
# 绘制三个子图,分别对应不同的学习率eta  
plt.subplot(131); plot_gradient_descent(theta, eta=0.02)  # 学习率0.02  
plt.ylabel("$y$", rotation=0, fontsize=18)  # 设置y轴标签  
plt.subplot(132); plot_gradient_descent(theta, eta=0.1, theta_path=theta_path_bgd)  # 学习率0.1,并记录theta路径  
plt.subplot(133); plot_gradient_descent(theta, eta=0.5)  # 学习率0.5  
  
# 显示图表  
plt.show()

这里面绘制了前10次迭代的情况,可以看到第一幅图,由于学习率很小,梯度下降进展很慢。第二幅图,可以看到当学习率适中时,梯度下降可以快速开始寻找最优解。第三幅图,当学习率比较大时,梯度下降很可能永远找不到最优解。

所以我们就记录了效果比较好的学习率0.1的theta变化过程,用来与其他方法的theta变化过程进行比较

4.随机梯度下降

# 初始化一个空列表,用于存储随机梯度下降过程中theta的路径
theta_path_sgd = []
# 获取数据点的数量
m = len(X_b)
np.random.seed(42)

# 设置训练的轮数(epoch) 
n_epochs = 50
# 定义学习率调度(learning schedule)的超参数 ,这些参数用于调整学习率随时间下降的速度
t0, t1 = 5, 50  

# 定义一个函数,用于根据当前的迭代次数计算学习率
def learning_schedule(t):
    return t0 / (t + t1)

# 随机初始化参数theta
theta = np.random.randn(2,1)  # random initialization

for epoch in range(n_epochs):
    for i in range(m):
        # 以下4行代码仅用于在第一个epoch的前20次迭代中绘制预测线
        if epoch == 0 and i < 20:                    # not shown in the book
            y_predict = X_new_b.dot(theta)           # not shown
            style = "b-" if i > 0 else "r--"         # not shown
            plt.plot(X_new, y_predict, style)        # not shown
        # 随机选择一个数据点的索引 
        random_index = np.random.randint(m)
        # 获取随机选择的数据点xi及其对应的标签yi
        xi = X_b[random_index:random_index+1]
        yi = y[random_index:random_index+1]
        # 计算梯度(注意这里由于只考虑了一个数据点,所以梯度是基于单个样本的)
        gradients = 2 * xi.T.dot(xi.dot(theta) - yi)
        # 根据当前的迭代次数(epoch * m + i)计算学习率 
        eta = learning_schedule(epoch * m + i)
        # 更新参数theta 
        theta = theta - eta * gradients
        # 将更新后的theta添加到路径列表中
        theta_path_sgd.append(theta)                 

plt.plot(X, y, "b.")                                
plt.xlabel("$x_1$", fontsize=18)                     
plt.ylabel("$y$", rotation=0, fontsize=18)           plt.axis([0, 2, 0, 15])                              
plt.show()  

说明:

初始化和设置:

theta_path_sgd = []:初始化一个空列表,用于存储随机梯度下降过程中theta的路径,即每次更新后的参数值。

m = len(X_b):获取数据点的数量。

np.random.seed(42):设置随机数种子,确保结果的可重复性。

n_epochs = 50:设置训练的轮数(epoch),即遍历整个数据集的次数。

t0, t1 = 5, 50:定义学习率调度的超参数,用于调整学习率随时间下降的速度。

学习率调度函数:

def learning_schedule(t)::定义一个函数,根据当前的迭代次数t计算学习率。这里的学习率随着迭代次数的增加而减小,这是一种常见的学习率衰减策略。

参数初始化:

theta = np.random.randn(2,1):随机初始化参数theta,这是一个2x1的向量,包含两个参数(一个是截距项,另一个是特征的系数)。

训练过程:

for epoch in range(n_epochs)::开始50轮的训练过程。

for i in range(m)::在每个epoch中,遍历每个数据点。

random_index = np.random.randint(m):随机选择一个数据点的索引,这是SGD中“随机”的由来。

xi = X_b[random_index:random_index+1]:获取随机选择的数据点xi。

yi = y[random_index:random_index+1]:获取对应的标签yi。

gradients = 2 * xi.T.dot(xi.dot(theta) - yi):计算梯度,这里只针对一个数据点计算。

eta = learning_schedule(epoch * m + i):根据当前的迭代次数计算学习率。

theta = theta - eta * gradients:更新参数theta。

theta_path_sgd.append(theta):将更新后的theta添加到路径列表中。

绘图:

plt.plot(X, y, "b."):绘制原始数据点。

plt.xlabel("$x_1$", fontsize=18):设置x轴标签。

plt.ylabel("$y$", rotation=0, fontsize=18):设置y轴标签。

plt.axis([0, 2, 0, 15]):设置坐标轴的范围。

plt.show():显示图表。

这段代码通过随机梯度下降算法训练线性回归模型,并在训练过程中记录参数的更新路径。学习率随着迭代次数的增加而减小,这有助于模型在训练初期快速收敛,在训练后期进行微调。最终,代码绘制了原始数据点和训练后的预测线。

# 观察经过随机梯度下降之后最后的theta
theta

sklearn下可以使用函数SGDRegressor实现随机梯度下降

SGDRegressor(

loss='squared_error', # 损失函数类型。可选的有 'squared_error', 'huber', 'epsilon_insensitive', 或 'squared_epsilon_insensitive'

*,

penalty='l2', # 惩罚(正则化)类型。可选的有 'none', 'l2', 'l1', 'elasticnet'。有助于防止模型过拟合。

alpha=0.0001, # 正则化强度的倒数(越大表示正则化强度越低)。仅在 penalty 不为 'none' 时使用。

l1_ratio=0.15, # 当 penalty 为 'elasticnet' 时,L1 和 L2 惩罚项之间的比例。仅在 penalty='elasticnet' 时使用

fit_intercept=True, # 是否计算截距项。如果为 False,则假定数据已经中心化

max_iter=1000, # 最大迭代次数。迭代将在达到最大迭代次数或满足其他停止条件时停止

tol=0.001, # 优化的容差。当损失或分数在 tol 内没有改进时,停止训练

shuffle=True, # 是否在每个迭代中随机打乱训练样本,有助于减少收敛到局部最小值的风险。

verbose=0, # 是否打印进度消息到 stdout。0 表示不打印,1 表示偶尔打印,>=2 表示对每个迭代都打印。

epsilon=0.1, # epsilon_insensitive 和 squared_epsilon_insensitive 损失函数的参数。仅当 loss 为这些类型之一时使用。

random_state=None, # 控制伪随机数生成器的种子

learning_rate='invscaling', # 学习率策略。可选的有 'constant', 'optimal', 'invscaling', 'adaptive'。

eta0=0.01, # 初始学习率。仅在 learning_rate='constant' 或 'invscaling' 时使用。

power_t=0.25, # 逆尺度学习率的指数。仅在 learning_rate='invscaling' 时使用。

early_stopping=False, # 是否使用早停来终止训练。如果为 True,则使用验证集上的性能来提前停止训练

validation_fraction=0.1, # 保留作为验证集的数据比例。仅在 early_stopping=True 时使用。

n_iter_no_change=5, # 在早停之前,验证分数在没有改进的情况下需要保持的迭代次数。仅在 early_stopping=True 时使用。

warm_start=False, # 当设置为 True 时,重用上一次调用的解决方案作为初始化,否则,重新分配并拟合一个新的模型

average=False, # 当设置为 True 时,计算所有迭代的平均系数。如果是一个整数,则计算最后 average 次迭代的平均系数。

)

from sklearn.linear_model import SGDRegressor
# Step1:构建SGDRegressor()估计器的实例对象sgd_reg
sgd_reg = SGDRegressor(max_iter=50, tol=None, penalty=None, eta0=0.1, random_state=42)
# Step2:调用实例对象sgd_reg的fit方法进行训练
sgd_reg.fit(X, y.ravel())

# Step2:通过intercept_和coef_查看训练得到的参数值,即线性方程的截断和系数
sgd_reg.intercept_, sgd_reg.coef_

第一个参数是截距b,第二个参数是系数k

5.小批量梯度下降

在迭代的每一步,批量梯度使用整个训练集,随机梯度使用仅仅一个实例,在小批量梯度下降中,它则使用一个随机的小型实例集。它比随机梯度的主要优点在于你可以通过矩阵运算的硬件优化得到一个较好的训练表现,尤其当你使用 GPU 进行运算的时候

# 初始化一个空列表,用于存储小批量梯度下降过程中theta的路径 
theta_path_mgd = []

# 设置迭代次数以及每个小批量(minibatch)的大小
n_iterations = 50
minibatch_size = 20

np.random.seed(42)
theta = np.random.randn(2,1)  # random initialization

t0, t1 = 200, 1000
def learning_schedule(t):
    return t0 / (t + t1)

# 初始化时间步t(用于学习率调度)  
t = 0
for epoch in range(n_iterations):
    # 在每一个迭代开始时,随机打乱数据点的索引 
    shuffled_indices = np.random.permutation(m)
    # 根据打乱后的索引,重新排列数据X_b和标签y 
    X_b_shuffled = X_b[shuffled_indices]
    y_shuffled = y[shuffled_indices]
    # 使用小批量梯度下降,遍历数据(以minibatch_size为步长)  
    for i in range(0, m, minibatch_size):
        # 更新时间步t
        t += 1
        # 获取当前小批量的数据点和对应的标签
        xi = X_b_shuffled[i:i+minibatch_size]
        yi = y_shuffled[i:i+minibatch_size]
        # 计算当前小批量的梯度(注意这里要除以minibatch_size进行归一化)
        gradients = 2/minibatch_size * xi.T.dot(xi.dot(theta) - yi)
        # 根据当前的时间步计算学习率 
        eta = learning_schedule(t)
        # 更新参数theta
        theta = theta - eta * gradients
        # 将更新后的theta添加到路径列表中  
        theta_path_mgd.append(theta)

# 观察经过小批量梯度下降之后最后的theta
theta

theta在此处是线性方程的两个参数b和k

6.三个方法的训练过程数据

# 转化为np.array数据类型
theta_path_bgd = np.array(theta_path_bgd)
theta_path_sgd = np.array(theta_path_sgd)
theta_path_mgd = np.array(theta_path_mgd)

plt.figure(figsize=(7,4))
plt.plot(theta_path_sgd[:, 0], theta_path_sgd[:, 1], "r-s", linewidth=1, label="Stochastic")
plt.plot(theta_path_mgd[:, 0], theta_path_mgd[:, 1], "g-+", linewidth=2, label="Mini-batch")
plt.plot(theta_path_bgd[:, 0], theta_path_bgd[:, 1], "b-o", linewidth=3, label="Batch")
plt.legend(loc="upper left", fontsize=16)
plt.xlabel(r"$\theta_0$", fontsize=20)
plt.ylabel(r"$\theta_1$   ", fontsize=20, rotation=0)
plt.axis([2.5, 4.5, 2.3, 3.9])
plt.show()

小结:全量梯度下降法的收敛效果是最好的,因为它将所有的情况都进行了考虑;随机梯度下降法的效果从图中也可以看出‘随机’的特点,收敛不稳定,可能并不能得到比较好的解;小批量梯度下降法则是两者的折中,在减少计算资源消耗的同时也在一定程度上确保了模型的收敛。

标签:plt,迭代,梯度,模型,random,np,构建,线性,theta
From: https://blog.csdn.net/yuange1666/article/details/144896758

相关文章

  • Spark Streaming + Elasticsearch构建App异常监控平台10
    如果在使用App时遇到闪退,你可能会选择卸载App、到应用商店怒斥开发者等方式来表达不满。但开发者也同样感到头疼,因为崩溃可能意味着用户流失、营收下滑。为了降低崩溃率,进而提升App质量,App开发团队需要实时地监控App异常。一旦发现严重问题,及时进行热修复,从而把损失降到最低。A......
  • Spark Streaming + Elasticsearch构建App异常监控平台15
    如果在使用App时遇到闪退,你可能会选择卸载App、到应用商店怒斥开发者等方式来表达不满。但开发者也同样感到头疼,因为崩溃可能意味着用户流失、营收下滑。为了降低崩溃率,进而提升App质量,App开发团队需要实时地监控App异常。一旦发现严重问题,及时进行热修复,从而把损失降到最低。A......
  • C#中的设计模式:构建更加优雅的代码
    C#在面向对象编程(OOP)方面的强大支持,我们可以探讨“C#中的设计模式”。这不仅有助于理解如何更好地组织代码,还能提高代码的可维护性和可扩展性。引言设计模式是软件工程中经过实践验证的解决方案模板,它们提供了一种标准化的方法来解决常见的开发问题。对于使用C#进行开发......
  • 故障诊断一区直接写,图卷积+BiGRU-Attention 并行诊断模型
    往期精彩内容:Python-凯斯西储大学(CWRU)轴承数据解读与分类处理基于FFT+CNN-BiGRU-Attention时域、频域特征注意力融合的轴承故障识别模型-CSDN博客基于FFT+CNN-Transformer时域、频域特征融合的轴承故障识别模型-CSDN博客Python轴承故障诊断(11)基于VMD+CNN-Bi......
  • 线性代数听课笔记
    基本定义线性空间线性相关、线性无关基矩阵的秩像空间与核空间(im,ker)线性代数基本定理高斯消元初等行变换相当于左乘一个特殊矩阵。求逆:对\((A|I)\)跑高斯-约旦,即可拿到\((I|A^{-1})\)。PLU分解:初等行变换里,『一行加到零一行』、『一行乘k』都可以表示为下三......
  • 网络_网络分层模型和应用协议
    网络分层模型和应用协议分层模型为了解决复杂问题往往分层经过不断的演化,网络最终形成了五层模型:MAC像指纹,出生之后就不变,每一层聚焦自己的问题IP地址动态唯一TCP可靠传输协议、UDP是广播协议应用层:应用到具体场景,不同场景建立了不同协议应对数据的传输:四层、七层、五......
  • python电影推荐系统 数据分析 大数据毕业设计 可视化大屏 爬虫 集成学习 Stacking模型
    博主介绍:✌全网粉丝10W+,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业项目实战6年之久,选择我们就是选择放心、选择安心毕业✌>......
  • Flask电影推荐系统 数据分析 可视化大屏 大数据毕业设计 爬虫 集成学习 Stacking模型
    博主介绍:✌全网粉丝10W+,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业项目实战6年之久,选择我们就是选择放心、选择安心毕业✌>......
  • docker 镜像上传下载,及构建java项目镜像心得
    docker在服务部署中是比较方便,并且在部署过程中出现问题的几率较低。本文对基础的docker项目部署做简单介绍1、安装docker和docker-compose,网上都有自行搜索2、拉取官方镜像①、拉官方镜像需要有镜像服务器,没有镜像服务器会报错,好用的镜像服务器都是收费的,不收费的大部分用不......
  • 构建PDF文件问答系统——从文档加载到检索增强生成
    技术背景介绍老铁们,相信你们都知道,PDF格式的文档在信息存储上有它的独有之处,尤其是那些长篇大论的年报或者技术白皮书之类。不过问题来了,这些文档里的非结构化数据本身不太容易直接喂给语言模型(LLM)。所以,今天我们就来聊聊如何搭建一个能从PDF文件中回答问题的系统——也就......