前言
早上没睡醒!又是在梦中被坏女人骗走感情的一天。
0、线性回归介绍以及使用步骤
0-1、线性回归介绍
线性回归是一种最基本的回归分析方法,旨在将一个或多个自变量与一个连续的因变量之间的关系建模为线性方程。该方法可以用于预测因变量的值,也可用于描述自变量和因变量之间的关系。
在线性回归中,我们假设自变量和因变量之间存在线性关系。这意味着,如果我们增加自变量的一个单位,那么因变量的值也将相应地增加一个固定的量。线性回归模型的基本形式如下:
其中,y是因变量的值,x1、x2、…、xn是自变量的值,β0、β1、β2、…、βn是模型的参数,ε表示误差项。
线性回归的目标是找到最佳的参数值,使得模型的预测值与实际值之间的差异最小化。通常使用最小二乘法来估计参数值,即通过最小化残差平方和来确定最佳的参数值。线性回归有如下特点:
- 线性回归的优点包括简单、易于解释和实现。
- 它也是许多其他高级回归方法的基础,如岭回归、Lasso回归和弹性网络回归等。
- 线性回归也有一些缺点,例如假设线性关系可能不适用于某些数据集,或者存在非线性关系
- 线性回归也容易受到离群值的干扰,需要进行数据清理和异常值检测。
总之,线性回归是一种基础的回归分析方法,可以用于建立自变量和因变量之间的线性关系模型,并对未来的数据进行预测。
0-2、使用步骤
当我们使用线性回归模型建立自变量和因变量之间的关系时,我们需要做以下几个步骤:
收集数据:我们需要收集自变量和因变量的数据,这些数据应该代表真实世界中的现象或事件。
理解数据:我们需要对数据进行探索性数据分析(EDA),以了解数据的统计特性、分布情况、异常值等。这有助于我们选择合适的模型和数据处理方法。
数据预处理:我们需要对数据进行预处理,包括缺失值填充、异常值检测和处理、数据标准化或归一化等等。
分离数据集:我们需要将数据集分成训练集和测试集,通常采用70:30的比例。
建立模型:我们需要建立线性回归模型,其中自变量和因变量之间的关系被建模为线性方程。最常用的方法是使用最小二乘法来估计模型的参数。
模型评估:我们需要对模型进行评估,以确定其性能和准确率。评估方法包括均方误差(MSE)、平均绝对误差(MAE)、R平方值等。
模型优化:如果模型的性能不够好,我们需要进行模型优化。优化方法包括引入新的特征、使用正则化方法(如岭回归和Lasso回归)来减少模型的复杂度、使用集成学习方法(如随机森林)来提高模型的准确率等。
模型预测:最后,我们可以使用训练好的模型来进行预测,以预测因变量的值。
一、一元线性回归
线性回归的定义:线性回归是一种通过自变量(一个或多个特征值)与因变量(目标值)之间的关系来进行建模的回归分析。
一元线性回归:即只用一个x来预测y,就是一元线性回归,一元线性回归的任务即找到一条直线(y = w x + b)来尽量的拟合图中的所有数据点。
二、损失函数
损失函数:损失函数是机器学习中一个重要的概念,它用于度量模型在训练数据上的性能。损失函数是一个将预测值和真实值作为输入的函数,它的输出是一个标量,表示模型在该预测值下的误差大小。损失函数越小,说明模型的预测结果越接近真实值。是用来评价直线对于图中所有数据点的拟合程度, 一般情况下,我们使用均方误差来评价直线的拟合程度,即均方误差的值越小,说明直线越能拟合我们的数据。
在训练模型时,我们的目标是最小化损失函数。通常采用梯度下降等优化算法来寻找最小化损失函数的模型参数。
常见的损失函数包括:
均方误差(Mean Squared Error,MSE):均方误差是回归问题中最常用的损失函数之一。它计算预测值和真实值之间的平方差,并将所有差值求和后取平均值。MSE越小,说明模型的预测结果越接近真实值。
平均绝对误差(Mean Absolute Error,MAE):平均绝对误差是另一个常用的回归问题损失函数。它计算预测值和真实值之间的绝对差,并将所有差值求和后取平均值。MAE比MSE更加鲁棒,因为它不受异常值的影响。
交叉熵(Cross-entropy):交叉熵是分类问题中的常用损失函数。它测量模型预测的概率分布与真实标签的概率分布之间的距离。当模型的预测值和真实值相同时,交叉熵为0。随着预测值和真实值之间的差异增大,交叉熵也会增大。
对数损失(Log Loss):对数损失是另一个常用的分类问题损失函数。它测量模型预测的概率分布与真实标签的概率分布之间的距离,但与交叉熵不同的是,对数损失将概率值取对数后再进行计算。
Hinge Loss:Hinge Loss是支持向量机(SVM)中使用的损失函数。它用于将数据分割成两个类别,计算每个数据点到分类边界的距离,并将距离差异转换为损失值。Hinge Loss对异常值具有鲁棒性,因为它只关注距离分类边界最近的数据点。
下边以均方误差为例:
MSE(Mean Square Error)均方误差:即真实值与预测值的差值的平方然后求和再平均
注:其中的黄色线代表真实值与预测值的差。
三、损失函数的优化方法(梯度下降)
梯度下降的定义:梯度下降是机器学习中的一种优化算法,用于寻找函数的最小值。在机器学习中,我们通常使用梯度下降算法来寻找损失函数的最小值,以便优化模型的参数。
梯度下降的基本思想是,从一个随机的起始点开始,沿着负梯度方向(导数值最小的方向)逐步迭代更新参数,直到达到损失函数的最小值。在梯度下降中,我们通过计算损失函数对每个参数的导数来确定下一步应该向哪个方向移动参数,以最小化损失函数。这个导数被称之为梯度,通过更新参数的值,我们可以逐步降低损失函数,直到达到一个局部最小值。
梯度下降的目的:不断学习改进,即梯度下降的目的,就是使得损失函数最小化。
梯度下降的原理:使用微积分里的导数,通过求出函数导数的值,从而找到函数下降的方向或者是最低点。
梯度下降有两种形式:批量梯度下降(BGD)和随机梯度下降(SGD)。在批量梯度下降中,每次迭代时,我们使用所有训练样本来计算损失函数和梯度,并更新参数。这种方法可以获得全局最优解,但是对于大规模数据集来说,计算成本很高。
相比之下,随机梯度下降每次只使用一个样本来计算梯度,并更新参数。这种方法计算成本低,但容易收敛到局部最优解。为了平衡这两个方法的优缺点,还有一种折中方法,称为小批量随机梯度下降(mini-batch SGD),它使用一小批数据来计算梯度,并更新参数
梯度下降的过程:
1、for 循环 to 训练次数(一般来说训练1000次,即较多次数,设置条件只要满足损失小于多少就停止):
2、随机生成权重w和偏差b,要求符合正态分布。(直接设置两个1也可以,后续会w和b会更新)。设置学习率,一般设置为(0.01, 0.1, 1)
3、计算每一个训练数据的预测值(y = w x + b),求得损失函数,并且计算每一个训练数据的权重和偏差相对于损失函数的梯度,即我们最终会得到每一个训练数据的权重和偏差的梯度值。
4、计算所有训练数据权重w的梯度的总和。
5、计算所有训练数据偏差b的梯度的总和。
6、求得所有样本的权重和偏差的梯度的平均值
7、根据公式来更新权重值和偏差值
8、循环,直到满足损失小于多少为止。
四、使用Torch来实现线性回归
import torch import matplotlib.pyplot as plt # 设置CPU生成随机数的种子,方便下次复现实验结果。 torch.manual_seed(9) # 设置学习率为0.1 lr = 0.05 # 创建训练数据 # 创建二维列表, x = torch.rand(20, 1)*10 y = 2*x + (5 + torch.randn(20, 1))
输出x和y:
# 随机参数w和b w = torch.randn((1), requires_grad=True) b = torch.randn((1), requires_grad=True)
输出w和b:
for i in range(1000): # 前向传播 # torch.mul作element-wise的矩阵点乘,维数不限,可以矩阵乘标量 # 当a, b维度不一致时,会自动填充到相同维度相点乘。 wx = torch.mul(w, x) # 支持广播相加 y_pred = torch.add(wx, b) # 计算MSE Loss # 反向传播, ✖2分之一是为了方便求导 loss = (0.5 * (y - y_pred) ** 2).mean() # 反向传播, 计算当前梯度 loss.backward() # 更新参数 # w = w- LR*w.grad # b = b- LR*w.grad # 函数形式:torch.sub(input, other, *, alpha=1, out=None) # 参数解读: # input: 输入的被减数,格式为tensor格式 # other:输入的减数 # alpha:与上面other参数搭配使用,用来与other相乘,当使用torch.sub()函数时不指定alpha的值时,alpha默认为1 # out: 指定torch.sub()输出值被赋给的变量,可不指定。 # 然而 # torch.sub_()功能与torch.sub()相同,区别在与torch.sub_()是torch.sub()的in-place操作版本。 b.data.sub_(lr * b.grad) w.data.sub_(lr * w.grad) # 绘图 if i % 20 == 0: plt.cla() # 防止社区版可视化时模型重叠2020-12-15 plt.scatter(x.data.numpy(), y.data.numpy()) plt.plot(x.data.numpy(), y_pred.data.numpy(), 'r-', lw=5) plt.text(2, 20, 'Loss=%.4f' % loss.data.numpy(), fontdict={'size': 20, 'color': 'red'}) plt.xlim(1.5, 10) plt.ylim(8, 28) plt.title("Iteration: {}\nw: {} b: {}".format(i, w.data.numpy(), b.data.numpy())) plt.pause(0.5) if loss.data.numpy() < 1: break plt.show()
迭代的最终图:
五、线性回归的从零开始实现(来源于花书)
5-1、生成 y = wx + b
import random import torch from d2l import torch as d2l import plotly.express as px import pandas as pd from sklearn.model_selection import train_test_split def synthetic_data(w, b, num_examples): #@save """生成y=Xw+b+噪声""" # torch.normal 是 PyTorch 中的一个函数,用于从正态(高斯)分布中生成随机数。 # 具体来说,它接受两个参数:均值(mean)和标准差(standard deviation),并返回一个张量,其中的元素是从指定分布中随机生成的。 # 生成num_examples组,每组的长度和w的长度相等。 X = torch.normal(0, 1, (num_examples, len(w))) # 在PyTorch中,torch.matmul 函数用于执行矩阵乘法运算。它接受两个张量作为输入,例如:torch.matmul(a, b), # 其中 a 和 b 可以是2D、3D或高维张量。两个输入张量必须满足一定的维度要求,以便矩阵乘法能够执行, # 否则会引发错误。比如说,当 a 是形状为 (n, m) 的 2D 张量,b 是形状为 (m, p) 的 2D 张量时, # torch.matmul(a, b) 将返回一个形状为 (n, p) 的 2D 张量,这个张量包含了矩阵乘法的结果。 y = torch.matmul(X, w) + b y += torch.normal(0, 0.01, y.shape) return X, y.reshape((-1, 1)) # 初始的w和b true_w = torch.tensor([2, -3.4]) true_b = 4.2 # 调用 # 得到我们要使用的特征和标签 features, labels = synthetic_data(true_w, true_b, 1000)
5-2、小批量生成函数
def data_iter(batch_size, features, labels): """ 该函数接收批量大小、特征矩阵和标签向量作为输入,生成大小为batch_size的小批量。 每个小批量包含一组特征和标签。 :param batch_size: :param features: :param labels: :return: """ # 特征数量 num_examples = len(features) # 特征索引 indices = list(range(num_examples)) # 这些样本是随机读取的,没有特定的顺序 # 随机清洗数据 random.shuffle(indices) for i in range(0, num_examples, batch_size): # 当前批次的一个索引下标 batch_indices = torch.tensor( indices[i: min(i + batch_size, num_examples)]) # 在 Python 中,"yield" 是一个关键字,用于定义生成器函数。生成器函数是一种特殊的函数, # 可以在函数执行期间产生多个值,而不是一次性返回所有的值。当生成器函数执行到 "yield" 语句时, # 它会暂停执行并将一个值返回给调用者。下次调用生成器函数时,它会从上一次暂停的位置继续执行,直到再次遇到 "yield" 语句。 yield features[batch_indices], labels[batch_indices]
5-3、线性回归模型、损失函数、优化函数定义
def linreg(X, w, b): #@save """ 线性回归模型 将模型的输入和参数同模型的输出关联起来。 """ return torch.matmul(X, w) + b def squared_loss(y_hat, y): #@save """均方损失""" return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2 def sgd(params, lr, batch_size): #@save """ 小批量随机梯度下降 从数据集中随机抽取的一个小批量,然后根据参数计算损失的梯度。接下来 朝着减小损失的方向更新我们的参数。 """ with torch.no_grad(): for param in params: param -= lr * param.grad / batch_size param.grad.zero_()
5-4、初始化w、b、批次并且进行训练
Notice:随机化w和b,通过训练, 计算小批量损失,反向传播,通过参数的梯度来更新参数,最终训练得到的w和b,与实际的w和b作差,得到w、b的估计误差。
# 设置批次为10 batch_size = 10 # 我们通过从均值为0、标准差为0.01的正态分布中采样随机数来初始化权重, 并将偏置初始化为0。 w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True) b = torch.zeros(1, requires_grad=True) # 开始训练: # 初始化参数 # 计算梯度并且更新参数。 lr = 1 num_epochs = 10 # 使用到的模型 net = linreg # 损失函数 loss = squared_loss for epoch in range(num_epochs): for X, y in data_iter(batch_size, X_train, y_train): l = loss(net(X, w, b), y) # X和y的小批量损失 # 因为l形状是(batch_size,1),而不是一个标量。l中的所有元素被加到一起, # 并以此计算关于[w,b]的梯度 l.sum().backward() sgd([w, b], lr, batch_size) # 使用参数的梯度更新参数 with torch.no_grad(): train_l = loss(net(X_train, w, b), y_train) print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}') print(f'w的估计误差: {true_w - w.reshape(true_w.shape)}') print(f'b的估计误差: {true_b - b}')
六、线性回归的简洁实现
6-1、生成 y = wx + b
import numpy as np import torch from torch.utils import data from d2l import torch as d2l true_w = torch.tensor([2, -3.4]) true_b = 4.2 features, labels = d2l.synthetic_data(true_w, true_b, 1000)
6-2、小批量生成函数
def load_array(data_arrays, batch_size, is_train=True): #@save """构造一个PyTorch数据迭代器""" dataset = data.TensorDataset(*data_arrays) return data.DataLoader(dataset, batch_size, shuffle=is_train) batch_size = 10 data_iter = load_array((features, labels), batch_size)
6-3、定义模型并初始化模型参数
# nn是神经网络的缩写 from torch import nn # 我们将两个参数传递到nn.Linear中。 第一个指定输入特征形状,即2,第二个指定输出特征形状,输出特征形状为单个标量,因此为1。 net = nn.Sequential(nn.Linear(2, 1)) # 使用net之前,我们需要初始化模型参数。如回归模型中的权重和偏置。我们通过net[0]选择网络中的第一个图层, 然后使用weight.data和bias.data方法访问参数。 我们还可以使用替换方法normal_和fill_来重写参数值。 net[0].weight.data.normal_(0, 0.01) net[0].bias.data.fill_(0)
6-4、定义损失函数和优化算法。
# 计算均方误差使用的是MSELoss类,也称为平方 # 范数。 默认情况下,它返回所有样本损失的平均值。 loss = nn.MSELoss() # 小批量随机梯度下降算法是一种优化神经网络的标准工具, PyTorch在optim模块中实现了该算法的许多变种。 当我们实例化一个SGD实例时,我们要指定优化的参数 (可通过net.parameters()从我们的模型中获得)以及优化算法所需的超参数字典。 小批量随机梯度下降只需要设置lr值,这里设置为0.03。 trainer = torch.optim.SGD(net.parameters(), lr=0.03)
6-5、训练
- 通过调用net(X)生成预测并计算损失l(前向传播)。
- 通过进行反向传播来计算梯度。
- 通过调用优化器来更新模型参数。
num_epochs = 3 for epoch in range(num_epochs): for X, y in data_iter: l = loss(net(X) ,y) trainer.zero_grad() l.backward() trainer.step() l = loss(net(features), labels) print(f'epoch {epoch + 1}, loss {l:f}') w = net[0].weight.data print('w的估计误差:', true_w - w.reshape(true_w.shape)) b = net[0].bias.data print('b的估计误差:', true_b - b)
参考文章:
线性回归,损失的定义,损失函数与优化方法,用统计学习方法来理解线性回归、损失函数和优化方法,Sklearn使用方法.
梯度下降算法(Gradient Descent)的原理和实现步骤.
总结
年纪大了,推个简单公式得写好久。