百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

Python实现机器学习算法——Lasso回归

bigegpt 2024-10-26 08:16 4 浏览

今天要介绍的是基于L1正则化的Lasso模型,在这之前,先带大家复习一下过拟合和正则化等机器学习关键问题。


正则化与L1范数

正则化是防止模型过拟合的核心技术之一,总的来说,监督机器学习的核心原理莫过于如下公式:

该公式可谓是机器学习中最核心最关键最能概述监督学习的核心思想的公式了:所有的有监督机器学习,无非就是正则化参数的同时最小化经验误差函数。

最小化经验误差是为了极大程度的拟合训练数据,正则化参数是为了防止过分的拟合训练数据。

正如之前所说,监督机器学习是为了让我们建立的模型能够发现数据中普遍的yiban的规律,这个普遍的一般的规律无论对于训练集还是未知的测试集,都具有较好的拟合性能。

继续回到公式:正则化xiang。第二项中 λ 为正则化系数,通常是大于 0 ,是一种调整经验误差项和正则化项之间关系的系数。

λ = 0 时相当于该公式没有正则化项,模型全力讨好第一项,将经验误差进行最小化,往往这也是最容易发生过拟合的时候。

随着 λ 逐渐增大,正则化项在模型选择中的话语权越来越高,对模型的复杂性的惩罚也越来越厉害。所以,在实际的训练过程中,λ 作为一种超参数很大程度上决定了模型的生死。

系数 λ 说完了,然后就是正则化项,正则化项形式有很多,但最常见的也就是 L1 和 L2 正则化。我们先来看L1。

再说常见的 L1 和 L2 之前,先来看一下 L0 正则化。L0 正则化也就是 L0 范数,即矩阵中所有非 0 元素的个数。如何我们在正则化过程中选择了 L0 范数,那该如何理解这个 L0 呢?

其实非常简单,L0 fanshu就是希望要正则化的参数矩阵 W 大多数元素都为 0。如此简单粗暴,让参数矩阵 W 大多数元素为 0 就是实现稀疏而已。

结论:在机器学习领域,L0 和 L1 都可以实现矩阵的稀疏性,但在实践中,L1 要比 L0 具备更好的泛化求解特性而广受青睐。

先说了 L1,但还没解释 L1 范数是什么,L1 范数就是矩阵中各元素绝对值之和,正如前述所言,L1 fan数通常用于实现参数矩阵的稀疏性。至于为啥要稀疏,稀疏有什么用,通常是为了特征选择和易于解释方面的考虑。



Lasso

Lasso的全称叫做Least absolute shrinkage and selection operator,直译过来为最小收缩与选择算子。其本质就是在常规的线性回归的基础上对参数加了一个L1正则化约束。其形式如下所示:

规约到线性回归模型上,上式的第一项就是MSE损失,第二项则是L1正则化项。我们同样按照之前线性回归的打法来对其进行实现,只是需要注意一下L1正则化项的求导处理。我们来看具体的实现代码

导入相关package并读入示例数据:

import numpy as np
import pandas as pd


data = np.genfromtxt('mystery.dat', delimiter = ',')
# 选择特征与标签
x = data[:,0:100] 
y = data[:,100].reshape(-1,1)
# 加一列
X = np.column_stack((np.ones((x.shape[0],1)),x))


# 划分训练集与测试集
X_train, y_train = X[:70], y[:70]
X_test, y_test = X[70:], y[70:]
print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)



定义参数初始化函数:

# 定义参数初始化函数
def initialize(dims):
    w = np.zeros((dims, 1))
    b = 0
    return w, b


定义符号函数并进行向量化,用于对L1正则化项的梯度计算:

# 定义符号函数
def sign(x):
    if x > 0:
        return 1
    elif x < 0:
        return -1
    else:
        return 0
 
# 利用numpy对符号函数进行向量化
vec_sign = np.vectorize(sign)
vec_sign(np.zeros((3,1))) 



在MSE损失函数的基础上定义Lasso损失:

# 定义lasso损失函数
def l1_loss(X, y, w, b, alpha):
    num_train = X.shape[0]
    num_feature = X.shape[1]
    y_hat = np.dot(X, w) + b
    loss = np.sum((y_hat-y)**2)/num_train + np.sum(alpha*abs(w))
    dw = np.dot(X.T, (y_hat-y)) /num_train + alpha * vec_sign(w)
    db = np.sum((y_hat-y)) /num_train
    return y_hat, loss, dw, db


定义Lasso训练过程函数:

# 定义训练过程
def lasso_train(X, y, learning_rate=0.01, epochs=300):
    loss_list = []
    w, b = initialize(X.shape[1])
    for i in range(1, epochs):
        y_hat, loss, dw, db = l1_loss(X, y, w, b, 0.1)
        w += -learning_rate * dw
        b += -learning_rate * db
        loss_list.append(loss)
        
        if i % 50 == 0:
            print('epoch %d loss %f' % (i, loss))
        params = {
            'w': w,
            'b': b
        }
        grads = {
            'dw': dw,
            'db': db
        }
    return loss, loss_list, params, grads


执行训练:

# 执行训练示例
loss, loss_list, params, grads = lasso_train(X_train, y_train, 0.01, 500)




可以看到,在L1的约束下,在训练过程中有不少对标签贡献率低的特征的系数都变成了0。这就是L1的作用,一定程度上可以进行特征选择和实现稀疏化。


最后可以简单写一个Lasso回归的class来对上述过程进行封装:

import numpy as np
from sklearn.metrics import r2_score




class Lasso():
    def __init__(self):
        pass
    
    def prepare_data(self):
        data = np.genfromtxt('./example.dat', delimiter = ',')
        x = data[:, 0:100]
        y = data[:, 100].reshape(-1, 1)
        X = np.column_stack((np.ones((x.shape[0], 1)), x))
        X_train, y_train = X[:70], y[:70]
        X_test, y_test = X[70:], y[70:]
        return X_train, y_train, X_test, y_test
    
    def initialize_params(self, dims):
        w = np.zeros((dims, 1))
        b = 0
        return w, b


    def sign(self, x):
        if x > 0:
            return 1
        elif x < 0:
            return -1
        else:
            return 0
        
    def l1_loss(self, X, y, w, b, alpha):
        num_train = X.shape[0]
        num_feature = X.shape[1]
        
        y_hat = np.dot(X, w) + b
        loss = np.sum((y_hat - y) ** 2) / num_train + np.sum(alpha*abs(w))
        dw = np.dot(X.T, (y_hat - y)) / num_train + alpha*np.vectorize(self.sign)(w)
        db = np.sum((y_hat - y)) / num_train
        return y_hat, loss, dw, db
    
    def lasso_train(self, X, y, learning_rate, epochs):
        loss_list = []
        w, b = self.initialize_params(X.shape[1])
        for i in range(1, epochs):
            y_hat, loss, dw, db = self.l1_loss(X, y, w, b, 0.1)
            w += -learning_rate * dw
            b += -learning_rate * db
            loss_list.append(loss)
            
            if i % 300 == 0:
                print('epoch %d loss %f' % (i, loss))
            
            params = {
                'w': w,
                'b': b
            }
            grads = {
                'dw': dw,
                'db': db
            }
        return loss, loss_list, params, grads
    
    
    def predict(self, X, params):
        w = params['w']
        b = params['b']
        y_pred = np.dot(X, w) + b
        return y_pred
    
if __name__ == '__main__':
    lasso = Lasso()
    X_train, y_train, X_test, y_test = lasso.prepare_data()
    loss, loss_list, params, grads = lasso.lasso_train(X_train, y_train, 0.01, 3000)
    print(params)
    y_pred = lasso.predict(X_test, params)
    print(r2_score(y_test, y_pred))


以上是基于numpy的手动实现Lasso的过程,下面再来看Lasso在sklearn中的实现。

# 导入线性模型模块
from sklearn import linear_model
# 创建lasso模型实例
sk_lasso = linear_model.Lasso(alpha=0.1)
# 对训练集进行拟合
sk_lasso.fit(X_train, y_train)
# 打印模型相关系数
print("sklearn Lasso intercept :", sk_lasso.intercept_)
print("\nsklearn Lasso coefficients :\n", sk_lasso.coef_)
print("\nsklearn Lasso number of iterations :", sk_lasso.n_iter_)



原文资料:

https://mp.weixin.qq.com/s/Ma8rWgwLrJ0sqSJzwvqUjA

相关推荐

Docker篇(二):Docker实战,命令解析

大家好,我是杰哥上周我们通过几个问题,让大家对于Docker有了一个全局的认识。然而,说跟练往往是两个概念。从学习的角度来说,理论知识的学习,往往只是第一步,只有经过实战,才能真正掌握一门技术所以,本...

docker学习笔记——安装和基本操作

今天学习了docker的基本知识,记录一下docker的安装步骤和基本命令(以CentOS7.x为例)一、安装docker的步骤:1.yuminstall-yyum-utils2.yum-con...

不可错过的Docker完整笔记(dockerhib)

简介一、Docker简介Docker是一个开源的应用容器引擎,基于Go语言并遵从Apache2.0协议开源。Docker可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,...

扔掉运营商的 IPTV 机顶盒,全屋全设备畅看 IPTV!

其实现在看电视节目的需求确实大大降低了,折腾也只是为了单纯的让它实现,享受这个过程带来的快乐而已,哈哈!预期构想家里所有设备直接接入网络随时接收并播放IPTV直播(电信点播的节目不是太多,但好在非常稳...

第五节 Docker 入门实践:从 Hello World 到容器操作

一、Docker容器基础运行(一)单次命令执行通过dockerrun命令可以直接在容器中执行指定命令,这是体验Docker最快捷的方式:#在ubuntu:15.10容器中执行ech...

替代Docker build的Buildah简单介绍

Buildah是用于通过较低级别的coreutils接口构建OCI兼容镜像的工具。与Podman相似,Buildah不依赖于Docker或CRI-O之类的守护程序,并且不需要root特权。Builda...

Docker 命令大全(docker命令大全记录表)

容器生命周期管理run-创建并启动一个新的容器。start/stop/restart-这些命令主要用于启动、停止和重启容器。kill-立即终止一个或多个正在运行的容器rm-于删除一个或...

docker常用指令及安装rabbitMQ(docker安装rabbitmq配置环境)

一、docker常用指令启动docker:systemctlstartdocker停止docker:systemctlstopdocker重启docker:systemctlrestart...

使用Docker快速部署Storm环境(docker部署confluence)

Storm的部署虽然不是特别麻烦,但是在生产环境中,为了提高部署效率,方便管理维护,使用Docker来统一管理部署是一个不错的选择。下面是我开源的一个新的项目,一个配置好了storm与mono环境的D...

Docker Desktop安装使用指南:零基础教程

在之前的文章中,我多次提到使用Docker来安装各类软件,尤其是开源软件应用。鉴于不少读者对此有需求,我决定专门制作一期关于Docker安装与使用的详细教程。我主要以Macbook(Mac平台)为例进...

Linux如何成功地离线安装docker(linux离线安装httpd)

系统环境:Redhat7.2和Centos7.4实测成功近期因项目需要用docker,所以记录一些相关知识,由于生产环境是不能直接连接互联网,尝试在linux中离线安装docker。步骤1.下载...

Docker 类面试题(常见问题)(docker面试题目)

Docker常见问题汇总镜像相关1、如何批量清理临时镜像文件?可以使用sudodockerrmi$(sudodockerimages-q-fdanging=true)命令2、如何查看...

面试官:你知道Dubbo怎么优雅上下线的吗?你:优雅上下线是啥?

最近无论是校招还是社招,都进行的如火如荼,我也承担了很多的面试工作,在一次面试过程中,和候选人聊了一些关于Dubbo的知识。Dubbo是一个比较著名的RPC框架,很多人对于他的一些网络通信、通信协议、...

【Docker 新手入门指南】第五章:Hello Word

适合人群:完全零基础新手|学习目标:30分钟掌握Docker核心操作一、准备工作:先确认是否安装成功打开终端(Windows用户用PowerShell或GitBash),输入:docker--...

松勤软件测试:详解Docker,如何用portainer管理Docker容器

镜像管理搜索镜像dockersearch镜像名称拉取镜像dockerpullname[:tag]列出镜像dockerimages删除镜像dockerrmiimage名称或id删除...