线性回归超详解

news2025/1/16 13:48:25

目录

一、回归问题 vs 分类问题

二、线性回归

1、一句话理解

2、数学推导

2.1 线性函数表示 

 2.2 损失函数

2.3 梯度下降

2.3.1 什么是梯度

2.3.2 梯度下降目标

 2.3.3 过程

2.3.4 迭代公式

3、特征预处理

3.1 为什么要预处理

3.2 数据归一化方法

1)最小-最大归一化

2)Z-Score 归一化

4、正则化 

4.1 为什么要正则化

4.2 L1 正则化

4.3 L2 正则化

5、回归问题的评估指标

均方误差

均方根误差

平均绝对误差

R 平方

三、代码实现

1、手动实现线性回归

2、使用sklearn库实现


一、回归问题 vs 分类问题

  • 监督学习(Supervised Learning): 样本数据带有标签值, 它从训练样本中学习得到一个模型, 然后用这个模型对新的样本进行预测推断。
  • 无监督学习(Unsupervised Learning): 对没有标签得数据进行分析, 发现样本集的结构或者分布规律。 比如数据降维, 我们会在后面的学习中介绍数据降维算法。
  • 分类问题: 如果样本的标签是整数, 则预测函数是一个向量到整数的映射。我们前面讲的判断水果是猕猴桃还是樱桃的问题就是分类问题。
  • 回归问题: 如果样本的标签是连续实数, 则预测函数是向量到实数的映射 

二、线性回归

1、一句话理解

线性回归是通过拟合一条直线函数(在多维空间中是超平面),来建立自变量和因变量之间线性关系的统计模型,以预测或解释因变量的变化。如下所示。

2、数学推导

以波士顿房价预测为例

输入X有两个特征,分别是房屋面积和卧室数量,输出为房屋价格

2.1 线性函数表示 

直线函数表示为:h(x) = \Theta _0+\Theta _1x_1+\Theta _2x_2 ,简化为h(x) = \sum_{i=0}^{d} \theta_i x_i

  • x_1表示房屋的面积,
  • x_2表示房屋的卧室数量,
  • x = \begin{bmatrix} x_0 \\ x_1 \\ x_2 \end{bmatrix}x_0=1
  • \Theta _i是线性函数的参数
  • \theta = \begin{bmatrix} \theta_0 \\ \theta_1 \\ \theta_2 \end{bmatrix}
  • d表示输入特征的数量

目的是找到合适的 \Theta使给定输入向量 x, 让 h(x)能够等于或者说接近目标值(标签) y。

 2.2 损失函数

作用:用于衡量预测结果与真实结果之间的误差, 它在训练过程中的作用是优化参数; 在预测阶段的作用是衡量模型的性能。

使用均方误差损失函数:

J(\theta) = \frac{1}{2n} \sum_{i=0}^{n} \left( h_{\theta}(x^{(i)}) - y^{(i)} \right)^2   i表示第i个样本

tips:这里有除以2操作,在2.3.4中会说到其作用

2.3 梯度下降

2.3.1 什么是梯度

梯度是导数对多元函数的推广,它是多元函数对每一个自变量偏导数形成的向量。梯度定义为:\nabla f(x) = \left[ \frac{\partial f}{\partial x_1}, \frac{\partial f}{\partial x_2}, \ldots, \frac{\partial f}{\partial x_n} \right]^T

梯度是向量, 因此是有方向的。 梯度的方向是函数值增长最快的方向

梯度下降法是沿着梯度向量的反方向进行迭代以达到函数的极值点。

2.3.2 梯度下降目标

我们的目标是最小化损失函数,即minimizeJ(\theta),当损失函数最小时,\Theta效果最好。使用梯度下降法来最小化损失函数从而计算参数\Theta

 2.3.3 过程

参数用 w 表示, 首先为参数 w 选择一个初始值, 然后不断改变 w的值, 使 J(w)减小。

2.3.4 迭代公式

x_{k+1} = x_k - \gamma \nabla f(x_k)

根据上述公式,知参数\Theta更新过程为:\theta \leftarrow \theta - \alpha \nabla J(\theta)

\alpha在机器学习中称为学习率, 学习率越大参数更新的速度越快, 模型训练的速度就越快, 但有可能导致模型不稳定或者训练效果不好; 学习率越小参数更新的速度越慢, 导致训练的时间过长, 所以在实际训练过程中应该选择合适的学习率。

参数 \Theta的每一个分量 \Theta_j更新方式表示为如下:

\theta_j \leftarrow \theta_j - \alpha \frac{\partial}{\partial \theta_j} J(\theta)

其中

\frac{\partial}{\partial \theta_j} J(\theta) = \frac{1}{2} \frac{\partial}{\partial \theta_j} (h_\theta(x) - y)^2 = (h_\theta(x) - y) \cdot \frac{\partial}{\partial \theta_j} (h_\theta(x) - y) = (h_\theta(x) - y) \cdot \frac{\partial}{\partial \theta_j} \left( \sum_{i=0}^{d} \theta_i x_i - y \right) = (h_\theta(x) - y) \cdot x_j
从这里可以看出除以2的目的是消除求导过程中产生的数字2,简化计算

\Theta_j更新方式可以简化成:

\theta_j \leftarrow \theta_j - \alpha \left( h_\theta(x^{(i)}) - y^{(i)} \right) x_j^{(i)},这里(i)表示第 i 个训练样本

代码如下:

def gradient_descent(X, y, theta, l, alpha, epoch):
    cost = np.zeros(epoch)  # 初始化一个ndarray,包含每次epoch的cost
    m = X.shape[0]  # 样本数量m
    for i in range(epoch):
        # 利用向量化一步求解
        theta = theta - (alpha / m) * (X * theta.T - y).T * X - (alpha * l / m) * theta  # 添加了正则项
        cost[i] = regularized_loss(X, y, theta, l)  # 记录每次迭代后的代价函数值
    return theta, cost

3、特征预处理

3.1 为什么要预处理

如果特征向量各分量的取值范围相差很大, 会影响算法的精度与训练时的收敛, 在计算时也可能会导致浮点数的溢出。例如h(x) = \Theta _0+\Theta _1x_1+\Theta _2x_2x_1取值在0.1~0.01、x_2取值在1000~2000,那么x_1效果会被x_2掩盖。

3.2 数据归一化方法

1)最小-最大归一化
 

2)Z-Score 归一化

基于数据的均值和标准差进行归一化
 

代码如下:

# 载入数据集
def loadData(filepath):
    """
    :param filepath: csv
    :return: X, y
    """
    data_list = pd.read_csv(filepath)
    # 使用Z-score对数据进行归一化处理
    data_list = (data_list - data_list.mean()) / data_list.std()
    return data_list

4、正则化 

4.1 为什么要正则化

为了防止过拟合, 可以为损失函数加上一个惩罚项, 对复杂的模型进行惩罚,从而降低模型的复杂度。

4.2 L1 正则化

通过向损失函数添加一个与权重向量的 L1 范数成正比的惩罚项来实现。

Loss\_Regularization = Loss(y, y\_pred) + \lambda \|\theta\|_1\lambda为惩罚系数, 是人工设定的大于 0 的数。

L1 范数表示所有分量的绝对值之和,如下:

4.3 L2 正则化

通过向损失函数添加一个与权重向量的 L2 范数成正比的惩罚项来实现。

Loss\_Regularization = Loss(y, y\_pred) + \lambda \|\theta\|_2\lambda为惩罚系数, 是人工设定的大于 0 的数。

L2 范数表示向量模长,如下: 

在实际使用时根号可以不适用以简化计算

代码如下:

# 定义损失函数
def loss_function(X, y, theta):
    inner = np.power(X * theta.T - y, 2)
    return np.sum(inner)/(2*len(X))

# 定义正则化代价函数,防止过拟合
def regularized_loss(X, y, theta, l):
    reg = (l / (2 * len(X))) * (np.power(theta[1:], 2).sum())
    return loss_function(X, y, theta) + reg

代码正则化项中也使用了除以2操作,作用同上 

5、回归问题的评估指标

均方误差

均方根误差

平均绝对误差

R 平方

用于衡量回归模型对测试数据的拟合程度, 其取值范围在 0~1 之间, 越接近 1 表示模型拟合得越好





 

三、代码实现

1、手动实现线性回归

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

# 载入数据集
def loadData(filepath):
    """
    :param filepath: csv
    :return: X, y
    """
    data_list = pd.read_csv(filepath)
    # 使用Z-score对数据进行归一化处理
    data_list = (data_list - data_list.mean()) / data_list.std()
    return data_list


# 划分训练集与测试集
def splitData(data_list, ratio):
    train_size = int(len(data_list) * ratio)
    # 生成一个随机排列的整数数组
    random_indices = np.random.permutation(len(data_list))
    # 使用随机排列的索引列表重新设定 DataFrame 的行顺序
    data_list = data_list.iloc[random_indices]
    trainset = data_list[:train_size]
    testset = data_list[train_size:]
    X_train = trainset.drop("MEDV", axis=1) #去除最后一列
    y_train = trainset["MEDV"]
    X_test = testset.drop("MEDV", axis=1)
    y_test = testset["MEDV"]
    return X_train, X_test, y_train, y_test


# 定义损失函数
def loss_function(X, y, theta):
    inner = np.power(X * theta.T - y, 2)
    return np.sum(inner)/(2*len(X))


# 定义正则化代价函数,防止过拟合
def regularized_loss(X, y, theta, l):
    reg = (l / (2 * len(X))) * (np.power(theta[1:], 2).sum())
    return loss_function(X, y, theta) + reg


# 定义梯度下降方法
def gradient_descent(X, y, theta, l, alpha, epoch):
    cost = np.zeros(epoch)  # 初始化一个ndarray,包含每次epoch的cost
    m = X.shape[0]  # 样本数量m
    for i in range(epoch):
        # 利用向量化一步求解
        theta = theta - (alpha / m) * (X * theta.T - y).T * X - (alpha * l / m) * theta  # 添加了正则项
        cost[i] = regularized_loss(X, y, theta, l)  # 记录每次迭代后的代价函数值
    return theta, cost


if __name__ == '__main__':
    alpha = 0.01  # 学习率
    epoch = 1000   # 迭代次数
    l = 50  # 正则化参数
    data_list = loadData('housing.csv')
    X_train, X_test, y_train, y_test = splitData(data_list, 0.8)
    # 添加偏置列,同时初始化theta矩阵
    X_train = np.matrix(X_train.values)
    y_train = np.matrix(y_train.values)
    y_train = y_train.reshape(y_train.shape[1], 1)
    X_test = np.matrix(X_test.values)
    y_test = np.matrix(y_test.values)
    y_test = y_test.reshape(y_test.shape[1], 1)
    X_train = np.insert(X_train, 0, 1, axis=1)
    X_test = np.insert(X_test, 0, 1, axis=1)
    theta = np.matrix(np.zeros((1, 14)))  # x的第二维维度为14,所以初始化theta为(1,14)
    final_theta, cost = gradient_descent(X_train, y_train, theta, l, alpha, epoch)
    print(final_theta)

    # 模型评估
    y_pred = X_test * final_theta.T
    mse = np.sum(np.power(y_pred - y_test, 2)) / (len(X_test))
    rmse = np.sqrt(mse)
    R2_test = 1 - np.sum(np.power(y_pred - y_test, 2)) / np.sum(np.power(np.mean(y_test) - y_test, 2))
    print('MSE = ', mse)
    print('RMSE = ', rmse)
    print('R2_test = ', R2_test)

    # 绘制迭代曲线
    plt.plot(np.arange(epoch), cost, 'r')
    plt.title('Error vs. Training Epoch')
    plt.ylabel('Cost')
    plt.xlabel('Iterations')
    plt.show()

    # 图例展示预测值与真实值的变化趋势
    t = np.arange(len(X_test))  # 创建等差数组
    plt.plot(t, y_test, 'r-', label='target value')
    plt.plot(t, y_pred, 'b-', label='predict value')
    plt.legend(loc='upper right')
    plt.title('Linear Regression', fontsize=18)
    plt.grid(linestyle='--')
    plt.show()

2、使用sklearn库实现

import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn import metrics
import math


# 载入数据集
def loadData(filepath):
    """
    :param filepath: csv
    :return: list
    """
    data_list = pd.read_csv(filepath)
    X = data_list.drop("MEDV", axis=1)
    y = data_list["MEDV"]
    return X, y


X, y = loadData('housing.csv')
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.8)

model = LinearRegression()
model.fit(X_train, y_train)
print("parameters:{}".format(model.coef_))
y_pred = model.predict(X_test)
print(y_pred)
print(y_test)

# 均方误差
mse = metrics.mean_squared_error(y_test, y_pred)
print(mse)

# 均方根误差
rmse = math.sqrt(mse)
print(rmse)

# 平均绝对误差
mae = metrics.mean_absolute_error(y_test, y_pred)
print(mae)

# R平方
r = metrics.r2_score(y_test, y_pred)
print(r)

result_file = {"prediction_value": y_pred}
result_file = pd.DataFrame(result_file)
result_file.to_csv("housing_predict.csv", index=False)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2277556.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《无锡布里渊分布式光纤传感技术:照亮能源领域新征程》

在全球能源格局加速变革、能源需求持续攀升的当下,保障能源系统的安全、高效运行成为重中之重。分布式光纤传感技术宛如一颗璀璨的科技新星,正以前所未有的姿态融入能源领域,重塑着能源开采、运输与监测的传统模式。 石油与天然气作为现代工…

win32汇编环境,窗口程序中组合框的应用举例

;运行效果 ;win32汇编环境,窗口程序中组合框的应用举例 ;比如在窗口程序中生成组合框,增加子项,删除某项,取得指定项内容等 ;直接抄进RadAsm可编译运行。重点部分加备注。 ;以下是ASM文件 ;>>>>>>>>>>>>…

PHP智慧小区物业管理小程序

🌟智慧小区物业管理小程序:重塑社区生活,开启便捷高效新篇章 🌟 智慧小区物业管理小程序是一款基于PHPUniApp精心雕琢的智慧小区物业管理小程序,它犹如一股清新的科技之风,吹进了现代智慧小区的每一个角落…

win10电脑 定时关机

win10电脑 定时关机 https://weibo.com/ttarticle/p/show?id2309405110707766296723 二、使用任务计划程序设置定时关机打开任务计划程序: 按下“Win S”组合键,打开搜索框。 在搜索框中输入“任务计划程序”,然后点击搜索结果中的“任务…

【数模学习笔记】插值算法和拟合算法

声明:以下笔记中的图片以及内容 均整理自“数学建模学习交流”清风老师的课程资料,仅用作学习交流使用 文章目录 插值算法定义三个类型插值举例插值多项式分段插值三角插值 一般插值多项式原理拉格朗日插值法龙格现象分段线性插值 牛顿插值法 Hermite埃尔…

​HPM6700——以太网通信lwip_udpecho_freertos_socket

1. 概述 本示例展示在FreeRTOS系统下的UDP回送通讯 PC 通过以太网发送UDP数据帧至MCU,MCU将接收的数据帧回发至PC 2. 硬件设置 使用USB Type-C线缆连接PC USB端口和PWR DEBUG端口 使用以太网线缆连接PC以太网端口和开发板RGMII或RMII端口 3. 工程配置 以太网端…

低代码独特架构带来的编译难点及多线程解决方案

前言 在当今软件开发领域,低代码平台以其快速构建应用的能力,吸引了众多开发者与企业的目光。然而,低代码平台独特的架构在带来便捷的同时,也给编译过程带来了一系列棘手的难点。 一,低代码编译的难点 (1…

FPGA 21 ,深入理解 Verilog 中的基数,以及二进制数与十进制数之间的关系( Verilog中的基数 )

目录 前言 一. 基数基础 1.1 基数介绍 2.1 基数符号 3.1 二进制数 二. 二进制与十进制数 三. 二进制数 3.1 定义寄存器类型变量 3.2 定义线网类型变量 3.3 赋值操作 3.4 解析二进制数为十进制数 四. 代码示例 五. 注意事项 六. 更多操作 前言 在Verilog中&#…

开始使用Panuon开源界面库环境配置并手写VS2019高仿界面

1. Panuon环境配置 1.1. 通过Nuget 安装 Panuon.WPF.UI1.2. xaml引用命名空间1.3. using Panuon.WPF.UI; 2. VS2019 view 2.1. 设置窗体尺寸和title2.2. 添加静态资源 2.2.1. 什么是静态资源 2.3. 主Grid 2.3.1. 盒子模型2.3.2. 嵌套布局 3. 总结 1. Panuon环境配置 1.1. 通…

blender导出镜头动作vmd

1 选中相机 2 在相机属性中找到 MMD摄像机工具 3 在弹窗中给 烘焙动画 打勾(图中没忘打了)点击确定 等待烘焙完成 4 烘焙结束后选中刚刚新增的物体 5 在mmd tools中点击 动作-导出(图中已经导出了,故显示灰色)

RabbitMQ确保消息可靠性

消息丢失的可能性 支付服务先扣减余额和更新支付状态(这俩是同步调用),然后通过RabbitMq异步调用支付服务更新订单状态。但是有些情况下,可能订单已经支付 ,但是更新订单状态却失败了,这就出现了消息丢失。…

重生之我在21世纪学C++—string

一、string 概念 string 字符串是一种更加高级的封装,string 字符串中包含大量的方法,这些方法可以使得字符串的操作变得更加简单。如果 string 使用的好,慢慢你就不想使用字符数组来存放字符串了,因为更简单嘛。 C 将字符串直接…

day10_Structured Steaming

文章目录 Structured Steaming一、结构化流介绍(了解)1、有界和无界数据2、基本介绍3、使用三大步骤(掌握)4.回顾sparkSQL的词频统计案例 二、结构化流的编程模型(掌握)1、数据结构2、读取数据源2.1 File Source2.2 Socket Source…

x86_64搭建ARM交叉编译工具链

点击上方"蓝字"关注我们 01、下载 >>> GCC 64位交叉编译下载:https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/ 喜欢那个版本自己找 02、简介 >>> 交叉编译器中“交叉”的意思就是在一个架构…

迅翼SwiftWing | ROS 固定翼开源仿真平台正式发布!

经过前期内测调试,ROS固定翼开源仿真平台今日正式上线!现平台除适配PX4ROS环境外,也已实现APROS环境下的单机飞行控制仿真适配。欢迎大家通过文末链接查看项目地址以及具体使用手册。 1 平台简介 ROS固定翼仿真平台旨在实现固定翼无人机决策…

IOS界面传值-OC

1、页面跳转 由 ViewController 页面跳转至 NextViewController 页面 &#xff08;1&#xff09;ViewController ViewController.h #import <UIKit/UIKit.h>interface ViewController : UIViewControllerend ViewController.m #import "ViewController.h" …

用 Python 自动化处理日常任务

&#x1f496; 欢迎来到我的博客&#xff01; 非常高兴能在这里与您相遇。在这里&#xff0c;您不仅能获得有趣的技术分享&#xff0c;还能感受到轻松愉快的氛围。无论您是编程新手&#xff0c;还是资深开发者&#xff0c;都能在这里找到属于您的知识宝藏&#xff0c;学习和成长…

Linux:地址空间(续)与进程控制

hello&#xff0c;各位小伙伴&#xff0c;本篇文章跟大家一起学习《Linux&#xff1a;地址空间与进程控制》&#xff0c;感谢大家对我上一篇的支持&#xff0c;如有什么问题&#xff0c;还请多多指教 &#xff01; 如果本篇文章对你有帮助&#xff0c;还请各位点点赞&#xff0…

链家房价数据爬虫和机器学习数据可视化预测

完整源码项目包获取→点击文章末尾名片&#xff01;

亿道三防丨三防笔记本是什么意思?和普通笔记本的优势在哪里?

三防笔记本是什么意思&#xff1f;和普通笔记本的优势在哪里&#xff1f; 在现代社会中&#xff0c;笔记本电脑已经成为人们工作和生活中不可或缺的一部分。然而&#xff0c;在一些特殊行业或环境中&#xff0c;普通笔记本电脑由于其脆弱性和对环境条件的敏感性&#xff0c;往…