手写算法-python代码实现Lasso回归

2023-10-26

Lasso回归简介

上一篇文章我们详细介绍了过拟合和L1、L2正则化,Lasso就是基于L1正则化,它可以使得参数稀疏,防止过拟合。其中的原理都讲的很清楚,详情可以看我的这篇文章。
链接: 原理解析-过拟合与正则化

本文主要实现python代码的Lasso回归,并用实例佐证原理。

Lasso回归分析与python代码实现

我们先生成数据集,还是用sklearn生成。

import numpy as np
from matplotlib import pyplot as plt
import sklearn.datasets

#生成100个一元回归数据集
x,y = sklearn.datasets.make_regression(n_features=1,noise=5,random_state=2020)
plt.scatter(x,y)
plt.show()

在这里插入图片描述
如上所示,生成了一个一元回归数据集,如果数据中混入了噪声,如:(手动添加5个噪声数据)

#加5个异常数据,为什么这么加,大家自己看一下生成的x,y的样子
a = np.linspace(1,2,5).reshape(-1,1)
b = np.array([350,380,410,430,480])

#生成新的数据集
x_1 = np.r_[x,a]
y_1 = np.r_[y,b]

plt.scatter(x_1,y_1)
plt.show()

在这里插入图片描述
这个时候,数据表现为这个样子,由于这几个数据是异常数据,所以我们的线性回归模型应该拟合下面的样本点,即最终的参数应该比较小,不应该因为加入了几个很异常的数据,导致参数发生很大的偏移,以这个图为例,就是不应该变得很大。
,下面用我们之前写好的线性回归类(python代码实现),来展示效果:

class normal():
    def __init__(self):
        pass

    def fit(self,x,y):
        m=x.shape[0]
        X = np.concatenate((np.ones((m,1)),x),axis=1)
        xMat=np.mat(X)
        yMat =np.mat(y.reshape(-1,1))

        xTx=xMat.T*xMat
        #xTx.I为xTx的逆矩阵
        ws=xTx.I*xMat.T*yMat
        
        #返回参数
        return ws
         


plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
clf1 =normal()
#拟合原始数据
w1 = clf1.fit(x,y)
#预测数据
y_pred = x * w1[1] + w1[0]

#拟合新数据
w2 = clf1.fit(x_1,y_1)
#预测数据
y_1_pred = x_1 * w2[1] + w2[0]

print('原始样本拟合参数:\n',w1)
print('\n')
print('新样本拟合参数:\n',w2)

ax1= plt.subplot()
ax1.scatter(x_1,y_1,label='样本分布')
ax1.plot(x,y_pred,c='y',label='原始样本拟合')
ax1.plot(x_1,y_1_pred,c='r',label='新样本拟合')
ax1.legend(prop = {'size':15}) #此参数改变标签字号的大小
plt.show()

在这里插入图片描述

W的第一个参数是截距,第二个参数是斜率,也就是系数,可以看到系数变大了很多,仅因为加入了几个噪声,模型的鲁棒性很差,泛化能力也差,出现了一定程度的过拟合。

我们再来看Lasso的表达式:
在这里插入图片描述
= 线性回归损失函数 + L1正则项,上一篇文章我们有分析过L1正则项的特点(本文前面有链接),参数λ是正则项系数,正则项对参数θ不是连续可导,一般情况下,有以下两种方式来求Lasso的参数,
1、坐标轴下降法
2、用最小角回归法
这里推荐一篇刘建平博士的博客,写得很清楚。
链接: Lasso回归算法: 坐标轴下降法与最小角回归法小结

坐标轴下降法的数学依据主要是这个结论(此处不做证明):一个可微的凸函数J(θ), 其中θ是nx1的向量,即有n个维度。如果在某一点θi,使得J(θ)在每一个坐标轴θi(i = 1,2,...n)上都是最小值,那么J(θi)就是一个全局的最小值。

1、python实现坐标轴下降法求解Lasso

我们采用坐标轴下降法来求参数:python代码实现如下:

#临时写的函数,要在引入一个copy包,进行深度拷贝
#大家写一份代码,把要引入的包全放在最前面
import copy

 def CoordinateDescent(x, y,epochs,learning_rate,Lambda):        
        m=x.shape[0]
        X = np.concatenate((np.ones((m,1)),x),axis=1)
        xMat=np.mat(X)
        yMat =np.mat(y.reshape(-1,1))
        
        
        w = np.ones(X.shape[1]).reshape(-1,1)
        
        
        for n in range(epochs):
            
            
            out_w = copy.copy(w)
            for i,item in enumerate(w):
                #在每一个W值上找到使损失函数收敛的点
                for j in range(epochs):
                    h = xMat * w 
                    gradient = xMat[:,i].T * (h - yMat)/m + Lambda * np.sign(w[i])
                    w[i] = w[i] - gradient* learning_rate
                    if abs(gradient)<1e-3:
                        break
            out_w = np.array(list(map(lambda x:abs(x)<1e-3, out_w-w)))
            if out_w.all():
                break
        return  w

CoordinateDescent()函数来实现我们的Lasso回归,示例:

当Lambda参数为0时,也就是不加L1正则项时,就是普通的线性回归,参数输出都是一样的,也是47点多

#Lambda=0时;
w = CoordinateDescent(x_1,y_1,epochs=250,learning_rate=0.001,Lambda=0)
print(w)

#计算新的拟合值
y_1_pred = x_1 * w[1] + w[0]

ax1= plt.subplot()
ax1.scatter(x_1,y_1,label='样本分布')
ax1.plot(x,y_pred,c='y',label='原始样本拟合')
ax1.plot(x_1,y_1_pred,c='r',label='新样本拟合')
ax1.legend(prop = {'size':15}) #此参数改变标签字号的大小
plt.show()

在这里插入图片描述

当Lambda =10时,参数变为37点多;

#Lambda=10时;
w = CoordinateDescent(x_1,y_1,epochs=250,learning_rate=0.001,Lambda=10)
print(w)

#计算新的拟合值
y_1_pred = x_1 * w[1] + w[0]

ax1= plt.subplot()
ax1.scatter(x_1,y_1,label='样本分布')
ax1.plot(x,y_pred,c='y',label='原始样本拟合')
ax1.plot(x_1,y_1_pred,c='r',label='新样本拟合')
ax1.legend(prop = {'size':15}) #此参数改变标签字号的大小
plt.show()

在这里插入图片描述

当Lambda =30时,参数变为17点多,基本上已经和没添加异常值的参数是一样的了;

#Lambda=30时;
w = CoordinateDescent(x_1,y_1,epochs=250,learning_rate=0.001,Lambda=30)
print(w)

#计算新的拟合值
y_1_pred = x_1 * w[1] + w[0]

ax1= plt.subplot()
ax1.scatter(x_1,y_1,label='样本分布')
ax1.plot(x,y_pred,c='y',label='原始样本拟合')
ax1.plot(x_1,y_1_pred,c='r',label='新样本拟合')
ax1.legend(prop = {'size':15}) #此参数改变标签字号的大小
plt.show()

在这里插入图片描述

当Lambda =100时,参数基本上已经趋近于0,拟合线差不多就是一条水平线了;

#Lambda=100时;
w = CoordinateDescent(x_1,y_1,epochs=250,learning_rate=0.001,Lambda=100)
print(w)

#计算新的拟合值
y_1_pred = x_1 * w[1] + w[0]

ax1= plt.subplot()
ax1.scatter(x_1,y_1,label='样本分布')
ax1.plot(x,y_pred,c='y',label='原始样本拟合')
ax1.plot(x_1,y_1_pred,c='r',label='新样本拟合')
ax1.legend(prop = {'size':15}) #此参数改变标签字号的大小
plt.show()

在这里插入图片描述
正则项参数过大、过小都不好,
过小起不到惩罚效果,模型任然过拟合;
过大惩罚太大,会使得模型欠拟合,达不到要求;
我们选择参数的标准:模型在训练集、验证集、测试集上,评估效果接近时,这个正则项参数较好。

调用sklearn的Lasso回归对比

同样的,可以调用sklearn的Lasso回归来测试代码的正确性;
(只看参数的值,图就不画了)

from sklearn.linear_model import Lasso
lr=Lasso(alpha=0)
lr.fit(x_1,y_1)
print('alpha=0时',lr.coef_,'\n')

lr=Lasso(alpha=10)
lr.fit(x_1,y_1)
print('alpha=10时',lr.coef_,'\n')

lr=Lasso(alpha=30)
lr.fit(x_1,y_1)
print('alpha=30时',lr.coef_,'\n')

lr=Lasso(alpha=100)
lr.fit(x_1,y_1)
print('alpha=100时',lr.coef_)

在这里插入图片描述

基本上和我们的python代码实现的系数差不多。

2、近似梯度下降法python代码实现Lasso

只是在我们梯度下降法代码基础上,改了梯度的计算,加了sign(w),也就是加上L1正则项的导数);

class lasso():
    def __init__(self):
        pass
    
    #梯度下降法迭代训练模型参数,x为特征数据,y为标签数据,a为学习率,epochs为迭代次数
    def fit(self,x,y,a,epochs,Lambda):  
        #计算总数据量
        m=x.shape[0]
        #给x添加偏置项
        X = np.concatenate((np.ones((m,1)),x),axis=1)
        #计算总特征数
        n = X.shape[1]
        #初始化W的值,要变成矩阵形式
        W=np.mat(np.ones((n,1)))
        #X转为矩阵形式
        xMat = np.mat(X)
        #y转为矩阵形式,这步非常重要,且要是m x 1的维度格式
        yMat =np.mat(y.reshape(-1,1))
        #循环epochs次
        for i in range(epochs):
            gradient = xMat.T*(xMat*W-yMat)/m + Lambda * np.sign(W)
            W=W-a * gradient
        return W
    def predict(self,x,w):  #这里的x也要加偏置,训练时x是什么维度的数据,预测也应该保持一样
        return np.dot(x,w)

下面是运行的结果:
在这里插入图片描述
sklearn展示Lasso:

1、随着alpha值的增大,也就是正则项系数增大,系数变得越来越稀疏,更多的系数变为0。

#波士顿房价回归数据集
data =  sklearn.datasets.load_boston()
x =data['data']
y= data['target']

from sklearn.linear_model import Lasso
lr=Lasso(alpha= 1)
lr.fit(x,y)
print('当alpha=1时:\n',lr.coef_)

lr=Lasso(alpha= 5)
lr.fit(x,y)
print('当alpha=5时:\n',lr.coef_)

lr=Lasso(alpha= 10)
lr.fit(x,y)
print('当alpha=10时:\n',lr.coef_)

在这里插入图片描述

下一篇我们介绍Ridge回归。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

手写算法-python代码实现Lasso回归 的相关文章

随机推荐

  • protobuf的序列化和反序列化的分析

    一 protobuf的optional 数据类型序列化分析 1 optional 的protobuf的文件 格式 syntax proto2 message test proto optional int32 proto1 1 option
  • thinkphp5.0.24反序列化漏洞分析

    thinkphp5 0 24反序列化漏洞分析 文章目录 thinkphp5 0 24反序列化漏洞分析 具体分析 反序列化起点 toArray getRelationData分析 modelRelation生成 进入 call前的两个if c
  • 初步学习Oracle之PL/SQL

    PL SQL简介 PL SQL Procedure Language SQL 程序语言是 Oracle 对 sql 语言的过程化扩展 指在 SQL 命令语言中增加了过程处理语句 如分支 循环等 使 SQL 语言具有过程处理能力 把SQL 语
  • 【满分】【华为OD机试真题2023 JS】最差产品奖

    华为OD机试真题 2023年度机试题库全覆盖 刷题指南点这里 最差产品奖 知识点滑窗 时间限制 1s 空间限制 256MB 限定语言 不限 题目描述 A公司准备对他下面的N个产品评选最差奖 评选的方式是首先对每个产品进行评分 然后根据评分区
  • 在Android Studio中使用vulkan

    首先要确定手机是否支持Vulkan 可以下载一个aida64 在设备中如果能找到vulkan设备 说明支持 否则不支持 严格按照官方介绍的步骤一步步执行 就能获得官方推荐的可执行的例子 有很多 可以都试一试 那怎么在自己的工程中使用vulk
  • Vue模版语法&2种数据绑定方式

    Vue模板语法有2大类 1 插值语法 功能 用于解析标签体内容 写法 xx 其中xx是js表达式 且可以直接读取到data中的所有属性 p value p 在双大括号中 除了可以简单的传值外 还可以使用表达式 每个绑定都只能包含单个表达式
  • 中文新闻文本标题分类(基于飞桨、Text CNN)

    目录 一 设计方案概述 二 具体实现 三 结果及分析 四 总结 一 设计方案概述 主要网络模型设计 设计所使用网络模型为TextCNN 由于其本身就适用于短中句子 在标题分类这一方面应该能发挥其优势 TextCNN是Yoon Kim在201
  • R语言查看每列的缺失值

    代码 library tidyverse library naniar data gt miss var summary 注 gt 为管道函数 不懂可以看下面的链接 管道函数 miss var summary在naniar包里面
  • softwares

    视频切帧 变换分辨率 VLC 文件对比 Beyond Compare 远程控制 向日葵 TeamViewer
  • MATLAB安装配置MinGW-w64 C++编译器

    文章目录 前言 一 Mingw安装 1 安装教程 2 验证 二 MATLAB安装配置MinGW 总结 pic center 前言 只是为方便学习 不做其他用途 一 Mingw安装 在网上找到的安装一直报错 The file has been
  • uniapp(小程序)加载更多(LoadMore)在列表上的应用和刷新逻辑完善

    活动列表应用loadMore应用以及刷新逻辑完善 获取列表的方法会有3种状态 第一种是onLoad时 首屏的1页5条 第二种是加载更多触发的n页5条 以及第三种 当我们离开页面去往其他页面再回到列表页进行刷新触发的1页n条 首先先说加载更多
  • 全国DNS服务器IP地址大全、公共DNS大全

    各省公共DNS服务器IP大全 名称 各省公共DNS服务器IP大全 114 DNS 114 114 114 114 114 114 115 115 阿里 AliDNS 223 5 5 5 223 6 6 6 百度 BaiduDNS 180 7
  • 突发:香港警方警告 JPEX疑涉诈骗

    来源 香港明报 据香港明报跟进报道 未获发牌的 绿石数字资产平台 JPEX 涉疑违规在港宣传及经营 其后有客户表示提币失败 警务处长萧泽颐今日表示 警方前日收到证监会转介案件 因或涉及行骗成份 现由商业及罪案调查科跟进 至昨日下午3时收到8
  • 《UVM实战》学习笔记——第六章 sequence机制

    文章目录 前言 一 sequence的启动与执行 1 启动 2 启动方式 3 sequence分类 二 sequence的仲裁机制 1 sequence相关的宏 2 sequencer的仲裁算法 6种 3 sequence独占sequenc
  • USB HUB简述

    概述 hub 集线器 连接在host与device之间的一种用于usb接口扩展的usb设备 可以将一个usb上行接口扩展为多个下行接口 使得一个host可以同时与多个device连接 一般来说 一块hub桥接芯片可扩展4个usb接口 而市面
  • ‘dtools’不是内部或外部命令,也不是可运行的程序或批处理文件,个人解决方案

    powershell或cmd执行时出现 dtools 不是内部或外部命令 也不是可运行的程序或批处理文件 奇怪的是 我的工程目录下明明有dtools exe可执行文件 搜索引擎上多数反馈是添加C system32等路径到环境变量 但后续发现
  • 亲密关系-【沟通提示】-如何把学习到的东西用到生活中

    关于亲密关系 我学到了这么多 可为什么ta对这些毫不在意 我知道课里的观点都很重要 可我该怎么教会ta ta没有意识 看画面 案例 妈妈说话总是带有攻击性 总是骂她 怎么说 常见误区 你不要老师贬低我 对方苦苦思考 我到底该怎么办 你下意识
  • java中的多重循环

    多重循环 一个循环体内又包含另一个完整的循环结构 如下 while 循环条件1 循环操作1 while 循环条件2 循环操作2 do 循环操作1 do 循环操作2 while 循环条件2 while 循环条件1 for 循环条件1 循环操作
  • Docker - 使用Docker Compose部署应用

    简介 Docker Compose是一个基于Docker Engine进行安装的Python工具 该工具使得用户可以在一个声明式的配置文件中定义一个多容器的应用 在Docker节点上 以单引擎模式 Single Engine Mode 进行
  • 手写算法-python代码实现Lasso回归

    手写算法 python代码实现Lasso回归 Lasso回归简介 Lasso回归分析与python代码实现 1 python实现坐标轴下降法求解Lasso 调用sklearn的Lasso回归对比 2 近似梯度下降法python代码实现Las