首页 > 其他分享 >机器学习实战-手把手教会你如何用梯度下降实现线性回归

机器学习实战-手把手教会你如何用梯度下降实现线性回归

时间:2024-03-30 16:01:53浏览次数:20  
标签:迭代 手把手 np shape 梯度 线性 ax data

机器学习实战-利用梯度下降实现单变量线性回归

文章目录


前言

线性回归是一种统计学上的分析方法,用于确定两种或多种变量之间是否存在线性关系,模型的目标是找到自变量和因变量之间的最佳线性关系,以便能够用自变量的值来预测因变量的值。

这是一个机器学习单变量线性回归的一个练习,数据集是一个csv文件,有两列,一列是人口一列是收益,接下来便通过线性回归,用自变量的值来预测因变量的值。


一、导包

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

二、处理异常并导入数据集

1.处理异常

在 Matplotlib 中,中文字符和负号默认可能无法正常显示,这通常是因为 Matplotlib 的默认字体不支持中文,并且可能在处理负号时存在编码问题。因此,通常需要设置一些参数来确保中文和负号能够正确显示。

plt.rcParams['font.sans-serif']=['SimHei']#用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False#用来正常显示负号

第一行代码设置了 Matplotlib 中用于无衬线字体的默认字体为 ‘SimHei’。‘SimHei’ 是一种支持中文的字体,通过将其设置为默认字体,可以确保在图表中显示中文时不会出现乱码或缺失字符的问题。
第二行代码解决了负号显示的问题。在 Matplotlib 中,如果直接使用默认的字体设置,负号’-'可能会显示为方块或其他不正确的字符。通过将 axes.unicode_minus 设置为 False,Matplotlib 将使用传统的负号而不是试图从 Unicode 字体中查找它,从而避免了显示问题。

2.导入数据集

代码如下(示例):

path='D:\学习资料\机器学习\单变量线性回归\regress_data1.csv'
data=pd.read_csv(path)

把path设置成你自己电脑上的regress_data1.csv存储路径,如果报错OSError: [Errno] Invalid argument,说明是在转义的时候出现了问题,编译器把这个’'当成了转义字符。
此时的三种解决方案:

# 方法一:使用原始字符串:在字符串前加上 r 来告诉Python不要处理反斜杠作为转义字符。
path=r'D:\学习资料\机器学习\单变量线性回归\regress_data1.csv'
# 方法二:使用双反斜杠:用两个反斜杠 \\ 来代替一个,这样第一个反斜杠会转义第二个反斜杠,从而得到一个实际的反斜杠字符。
path='D:\\学习资料\\机器学习\\单变量线性回归\\regress_data1.csv'
# 方法三:使用正斜杠:在Python中,对于Windows路径,也可以使用正斜杠 / 而不是反斜杠 \。
path='D:/学习资料/机器学习/单变量线性回归/regress_data1.csv'

3.查看是否导入成功

print(data.head())

会得到:
在这里插入图片描述

data.describe() # 查看各列的描述性信息

会得到:在这里插入图片描述
其中,调用这个describe()方法时,它会返回关于数值列的一些统计信息,包括计数(count)、均值(mean)、标准差(std)、最小值(min)、25% 分位数(25%)、中位数(50% 或 median)、75% 分位数(75%)和最大值(max)。

4.绘制人口-收益图,可视化查看

data.plot(kind='scatter',x='人口',y='收益',figsize=(12,8)) # figsize=(),将画出的图片的大小设置为12英寸*8英寸
plt.xlabel('人口',fontsize=18)
plt.ylabel('收益',rotation=0,fontsize=18) # rotation改善可读性,决定了标签文本相对于水平线的旋转角度,0是水平,90则是垂直,也可以45,-45等
plt.show()

会得到:
在这里插入图片描述

三、使用梯度下降来实现线性回归,以最小化代价函数

1.定义方法计算代价函数

在这里插入图片描述
首先呢,X是一个特征矩阵,通常是一个二维数组,每一行代表一个样本,每一列代表一个特征;y是真实标签值,通常是一个一维数组,每个元素对应x中的一个样本的真实输出;w是权重向量,一维的,长度与X的列数(即特征数)相同。

其次呢,w.T是w这个行向量的转秩,就会变成列向量,再与矩阵X相乘,就是m行n列的矩阵与一个n行m列的矩阵相乘,得到的是一个m行1列的列向量。

再其次,(Xw.T)-是算其与真实值的误差,再用power(((Xw.T)-y),2)把误差平方,保证是一个正数。

最后呢,返回的是平均平方误差,即线性回归模型在当前权重w下的代价。X.shape()会返回一个二元组(m,n),即说明X的行数是m,列数是n,这里用的X.shape[0],就是X的行数。

def computeCost(X,y,w): 
    inner=np.power(((X*w.T)-y),2) # 算与真实值之间的误差再平方 (m,n) * (n, 1) -> (m, 1)
    return np.sum(inner)/(2*X.shape[0]) # X.shape[0]是X的行数,最后返回的是平均平方误差,即线性回归模型在当前权重w下的代价

2.添加偏置项

加上一行偏置项,当我们将数据表示为矩阵形式时,偏置项可以方便地作为一个额外的列添加到特征矩阵(X)中,其中这一列的所有值都是1。这样,我们就可以通过矩阵乘法来计算预测值。

通过添加偏置项,我们可以确保模型能够拟合数据的任何固定偏移,而不仅仅是特征之间的线性关系。这对于许多实际问题都是非常重要的,因为数据中通常包含一个不依赖于任何特征的固定部分,也就是线性方程y=k*x+b中的b。

data.insert(0,'ones',1)
print(data) # 输出一下data,看看是否正确插入了

会得到:
在这里插入图片描述

3.分离特征和目标变量(变量初始化)

接下来要对变量进行初始化,要把X设置为训练集数据,y设置为目标变量。
iloc函数是基于整数位置的索引,它接受行和列的整数位置,通常有两个参数:第一个参数用于选择行,第二个参数用于选择列。

前面说过shape会返回一个元组,所以shape[1]就是data的列数。

通常情况下,我们把除了最后一列之外的所有列视为特征,也就是赋值给X;将最后一列视为目标变量或标签,也就是y。

# set X(traindata) and y (target variable)
cols=data.shape[1] # data的列数存入cols
X=data.iloc[:,:cols-1] # 第一个冒号代表所有行,第二个代表从第一列到倒数第二列
y=data.iloc[:,cols-1:] # 第一个冒号代表所有行,第二个代表选取最后一列
# 经过这样处理后特征(X),目标变量(y)

接下来简单查看一下,看看是否分离特征成功。

print(X.head())

会得到:
在这里插入图片描述

print(y.head())

会得到:
在这里插入图片描述
接下来使用numpy中的matrix函数把X、y、w,全部转化为矩阵,并查看他们的形状是否正确符合要求。注意:这里的np.array([0,0]),相当于就是一个一维数组,只有两个值都是0。

X=np.matrix(X.values)
y=np.matrix(y.values)
w=np.matrix(np.array([0,0])) # 这里的意思是,一个矩阵,一行二列,都是0
print(X.shape,w.shape,y.shape)

会得到:
在这里插入图片描述
这个其实很对,这个数据集有97行3列,X选的是除了最后一列前面所有,所有共有两列;而w是只有两个元素的一维数组,也是对的;y选的是最后一列,也没问题。并且矩阵X乘上矩阵w的转秩矩阵,即(97,2)*(2,1)得到(97,1),刚好与上面结果相符合,所以是正确的。

4.使用批量梯度下降来计算结果

在这里插入图片描述

我们首先需要按照上面的公式定义一个批量梯度下降函数,如下:

def batch_gradientDescent(X,y,w,alpha,iters): 
    temp=np.matrix(np.zeros(w.shape)) # 用于存储每次迭代更新后的权重
    parameters=int(w.ravel().shape[1]) # 获取权重向量的参数个数即特征的数量,ravel是将多维转成一维的,shape[1]返回列数,也就是特征数
    cost=np.zeros(iters) # 用于存储每次迭代的代价(损失)
    for i in range(iters):
        error=(X*w.T)-y  # 计算误差值
        for j in range(parameters):
            term=np.multiply(error,X[:,j]) # 对于每个特征,计算误差与特征值的乘积
            temp[0,j]=w[0,j]-((alpha/len(X))*np.sum(term)) # 更新权重
        w=temp # 临时权重赋值给权重向量
        cost[i]=computeCost(X,y,w)
    return w,cost

在这个函数中,w是权重向量,梯度下降的过程中会更新;alpha是学习速率,控制每次更新权重的步长;iters是迭代次数,即每次下降算法需要的运行次数。而temp是个临时权重,先构建一个与w的形状相同的全是0的矩阵temp,并把特征数赋值给parameters,用cost存储每次迭代的损失值。在迭代过程中,不断计算每次迭代的误差值,更新权重。
这里返回的权重w的第一个元素就是截距项,即k*x+b中的b,返回的第二个元素是斜率,即k

5.代入拟合的参数计算训练模型的误差

alpha=0.01 # 学习速率
iters=1000 # 迭代次数
g,cost=batch_gradientDescent(X,y,w,alpha,iters)
print(g)
print(computeCost(X,y,g)) # 输出训练模型的代价函数

会得到:
在这里插入图片描述
我们也可以根据需要,改变学习速率和迭代次数,以此来达到自己预期的效果。

6.可视化输出结果

(1)线性回归散点图(线性回归拟合图)

通过如下代码画出线性回归散点图/拟合图。其中,f相当于y=k*x+b中的y,g[0,0]是b,g[0,1]是k。

x=np.linspace(data['人口'].min(),data['人口'].max(),100) # x值是从人口的min到人口的max,均匀选出100个点
f=g[0,0]+(g[0,1]*x) # g是一行二列的w,g[0,0]是第一个元素,即截距项,g[0,1]是对应于x的斜率,f是预测值
fig,ax=plt.subplots(figsize=(12,8))
ax.plot(x,f,'r',label='预测值')
ax.scatter(data['人口'],data['收益'],label='训练数据')
ax.legend(loc=2) # 添加图例,并设置其位置为2(通常表示图例位于左上角),1234分别对应第一二三四象限,可以根据需要把图例放在想要的位置
ax.set_xlabel('人口',fontsize=18)
ax.set_ylabel('收益',rotation=0,fontsize=18)
ax.set_title('预测收益和人口规模',fontsize=18)
plt.show()

会得到:
在这里插入图片描述
在这个图中:

  1. 红色的线是通过线性回归模型得到的预测值,它表示了“人口”与“收益”之间的线性关系。
  2. 散点图表示了实际的数据点,即每一个点都代表了一个实际的人口规模和对应的收益。
  3. 图例(legend)标明了哪些内容是预测值,哪些是训练数据。

(2)代价随迭代次数变化图(损失函数随迭代次数变化图)

用以下代码可以绘制代价随迭代次数变化图(损失函数随迭代次数变化图),可以很直观的看到代价随迭代次数变化的规律

fig,ax=plt.subplots(figsize=(12,8)) # subplot和plot的主要区别在于subplot用于在同一画布上创建多个绘图区域,而plot则用于在单个绘图区域中绘制图形。
ax.plot(np.arange(iters),cost,'r') # np.arange(iters)生成了一个从0到iters-1的整数数组,这些整数代表了迭代的次数;arange生成等差数列
ax.set_xlabel('迭代次数',fontsize=18)
ax.set_ylabel('代价',rotation=0,fontsize=18)
ax.set_title('误差和训练Epoch数',fontsize=18)
plt.show()

会得到:
在这里插入图片描述


总结

本文用批量梯度下降对单变量线性回归进行了拟合,拟合结果也还不错。如果有哪里没有讲清楚的,欢迎您在评论区留言探讨;如果您感觉本文讲述的还比较清晰,希望您能给本文点个赞,谢谢!

标签:迭代,手把手,np,shape,梯度,线性,ax,data
From: https://blog.csdn.net/m0_74277350/article/details/137171876

相关文章

  • 线性回归从零开始(麻雀虽小五脏俱全)
    目录构造数据集初始化模型参数定义模型定义损失函数定义优化算法训练过程线性回归是一个很好能理解深度学习的模型,麻雀虽小五脏俱全。构造数据集defsynthetic_data(w,b,num_examples):X=torch.normal(0,1,(num_examples,len(w)))y=torch.matmul(X,w)+by......
  • 神经网络与深度学习 Chapter2 线性分类与感知机
    Chapter2线性分类与感知机2.1线性回归线性回归定义:利用数理统计中回归分析,来确定两种或两种以上变量间相互依赖的定量关系的一种统计分析方法。线性回归要素:训练集(或训练数据),一般记为x......
  • 手把手教你做阅读理解题-初中中考阅读理解解题技巧005-attract people to join Fitnes
    PDF格式公众号回复关键字:ZKYD005阅读理解技巧,在帮助读者有效获取和理解文本信息方面发挥着重要作用,熟练掌握如下6个技巧,可快速突破阅读理解1预览文章结构在开始深入阅读之前,快速浏览文章的标题、段落开头和结尾,可以迅速把握文章的主题、大致内容和结构标题通常能概括文章......
  • 数据结构之————线性表ADT、以数组存储方式实现抽象类型的一个实例
    前言:基础填坑1、ADT在文章开始前,我们要弄明白什么是ADT(AbstractDataType)抽象数据类型1、ADT是用户定义的数据类型,它包含一组数据以及在这组数据上进行的操作。只定义操作的行为,没有具体的实现细节2、它存在的目的是使我们能够独立于程序的实现细节来理解数据结构的特......
  • R语言广义线性混合模型(GLMM)bootstrap预测置信区间可视化
    全文链接:https://tecdat.cn/?p=35552原文出处:拓端数据部落公众号通过线性模型和广义线性模型(GLM),预测函数可以返回在观测数据或新数据上预测值的标准误差。然后,利用这些标准误差绘制出拟合回归线周围的置信区间或预测区间。置信区间(CI)的重点在于回归线,其可以解释为(假设我们绘制的......
  • 你问我答!手把手教学,银河麒麟桌面操作系统编译安装BIMP插件过程详解
    (引言:银河麒麟应热心用户后台提问,推出银河麒麟桌面操作系统编译安装BIMP插件详解过程详解专题。如有其它问题和需求,欢迎后台留言咨询……)1.GIMP简介GIMP是GNU图像处理程序(GNUImageManipulationProgram)的缩写。包括几乎所有图象处理所需的功能,号称Linux下的PhotoS......
  • 我做【网创导师训练营】项目,从0开始做,3个月就做到月入10万+,现在手把手复制给你
    一、开门见山,先公开一下我自己操作的收益大家好!我是如今,【如今笔记】的主理人。今天给大家带来的项目是:网创导师训练营。我是从0开始做的这个项目,三个月的时间,我做到了月收益10万以上,而且现在每月的收益都还在增加。 这个项目比较简单,不需要你有很多的设备,一台手机+一台电......
  • 逻辑回归中交叉熵损失函数的梯度
    要给出逻辑回归中交叉熵损失函数最小化的梯度推导过程,我们首先定义损失函数和模型预测的形式。对于二分类逻辑回归,模型预测使用sigmoid函数,即:\[\hat{y}_i=\sigma(z_i)=\frac{1}{1+e^{-z_i}}\]其中,\(z_i=X_i\cdot\theta\)是模型对第\(i\)个样本的线性预测,\(X_i\)是样本......
  • 自己写个网盘系列:③ 开源这个网盘编码,手把手教你windows linux 直接部署,docker本地打
    ❤系列①②已经完成了这个项目的页面和项目的全部编码,前后端分离,这个文章将向你展示运维小伙伴如何部署到windows服务器,linux服务器,docker部署,一学就会,快来看看吧!❤说明:这个系列准备用Simple快速框架搞个自己能用的网盘,来个实战,教大家如何搞一个项目,其中你能学到如何进行项目......
  • 《手把手教你》系列技巧篇(五十九)-java+ selenium自动化测试 - 截图三剑客 -上篇(详细教
    1.简介今天本来是要介绍远程测试的相关内容的,但是宏哥在操作服务器的时候干了件糊涂的事,事情经过是这样的:本来申请好的Windows服务器用来做演示的,可是服务器可能是局域网的,连百度都不能访问,宏哥想调试一下网络,禁用网卡,然后重启网卡,结果禁用后就连不上了。。。。就只能等服......