【机器学习】主成分分析法(PCA)

【机器学习】主成分分析法(PCA)

  • 一、摘要
  • 二、主成分分析的基本概念
  • 三、主成分分析的数学模型
  • 五、主成分分析法目标函数公式推导(`梯度上升法`求解目标函数)
  • 六、梯度上升法求解目标函数第一个主成分
  • 七、求解前n个主成分及PCA在数据预处理中的处理步骤(后续实现)

一、摘要

本文主要讲述了主成分分析法(PCA)的原理和应用。PCA通过选择最重要的特征,将高维数据映射到低维空间,同时保持数据间的关系,实现降维和去噪。通过具体的例子和图示解释了PCA的原理,并比较了两种降维方案,解释了为什么选择将数据映射到x轴上可以得到更好的分类效果。最后强调了在PCA之前需要对所有样本的均值进行归零处理。通过这篇文章,读者可以深入了解PCA的原理和应用,并掌握如何使用PCA进行数据降维和去噪,提高分类效果。

二、主成分分析的基本概念

  1. 定义
    PCAPrincipal Component Analysis)即主成分分析,是机器学习中一种常用的数据分析技术,PCA 是一种无监督的线性降维算法它通过线性变换将原始数据转换为一组新的特征,这些新特征被称为主成分,它们是原始特征的线性组合,并且在尽可能保留原始数据信息的前提下实现数据维度的降低
  2. 作用
    • 数据降维:在很多实际应用中,数据的维度可能非常高,这会导致计算量增大、模型训练时间变长以及可能出现的过拟合等问题。PCA 可以将高维数据映射到低维空间,在保留大部分关键信息的同时,大大减少数据的维度,提高计算效率和模型性能。
    • 去除噪声和冗余:原始数据中往往存在一些噪声和冗余信息,这些信息可能会干扰模型的训练和预测。PCA 通过提取主成分,可以去除一些与其他特征高度相关的冗余信息,以及一些对数据整体结构影响较小的噪声,使数据更加干净和易于处理。
    • 数据可视化:对于高维数据,很难直接进行可视化展示。通过 PCA 将数据降维到二维或三维空间后,可以方便地进行数据可视化,帮助人们直观地理解数据的分布和结构,发现数据中的潜在规律和异常点。
  3. 底层原理
    • 协方差矩阵与特征值分解首先计算原始数据的协方差矩阵,协方差矩阵可以衡量各个特征之间的相关性。然后对协方差矩阵进行特征值分解,得到特征值特征向量特征值表示对应主成分方差大小特征向量则表示主成分方向
    • 主成分的选取:按照特征值从大到小顺序特征向量进行排序,选择前k个特征向量作为主成分,其中k是降维后想要得到的维度。这些主成分所对应的特征值较大,意味着它们能够解释原始数据中较大比例的方差,即包含了原始数据的大部分重要信息。
    • 数据投影:将原始数据投影到选取的主成分张成子空间上,就得到了降维后的数据。具体来说,对于原始数据中的每个样本,通过与主成分对应的特征向量进行线性变换,将其映射到新的低维空间中。
  4. 补充方差的概念
    1. 方差的意义:方差是数据点与其平均值之间差异的平方的平均数。它反映了数据分布的分散程度。
    2. 方差大 vs 方差小
      • 方差大:数据点远离均值,分布广泛,样本显得稀疏。
      • 方差小:数据点接近均值,集中分布,样本显得紧密。
    3. 图形化理解:高方差的数据通常在图表中表现为更长的尾巴或更大的范围,而低方差则集中在中间区域。
      结论:方差越大,样本间越稀疏;方差越小,样本间越紧密。

三、主成分分析的数学模型

  1. PCA的目标是找到一个方向向量w,使得所有样本映射到该方向后方差最大。而PCA寻找最大方差方向,进行数据降维。
    在这里插入图片描述

  2. 映射后的样本方差计算公式为每个样本与方向向量w的点积的平方和除以样本数量m。 映射过程可以通过几何方式解释,即将每个样本点垂直投影到目标方向向量w上。投影长度等于样本点与方向向量w的点积结果,反映了样本在该方向上的分布情况。
    在这里插入图片描述

  3. 当均值为零时,方差计算公式进一步简化为向量模的平方和除以m。
    在这里插入图片描述

五、主成分分析法目标函数公式推导(梯度上升法求解目标函数)

  1. 目标函数对每一个w求偏导数梯度):
    在这里插入图片描述

  2. 通过向量点乘后简化公式如下:
    在这里插入图片描述

  3. 通过进一步向量化点乘处理后,可以简化如下所示:
    在这里插入图片描述

  4. 最后来看下简化的梯度
    在这里插入图片描述

六、梯度上升法求解目标函数第一个主成分

  1. 生成测试数据集

    import numpy as np
    import matplotlib.pyplot as plt# 生成数据
    X = np.empty((100, 2))
    X[:, 0] = np.random.uniform(0., 100., size=100)
    X[:, 1] = 0.75 * X[:, 0] + 3. + np.random.normal(0, 10., size=100)# 绘制数据散点图
    plt.scatter(X[:, 0], X[:, 1])
    plt.show()
    

    效果:
    在这里插入图片描述

  2. 均值归零处理

    # 在进行PCA之前需要实现均值归一划处理,也就是将均值归零
    # 1. 定义均值归零的函数,定义了一个名为demean的函数,该函数接受一个数据集X作为参数。
    def demean(X):# return X - np.mean(X, axis=0) 是函数的主体部分。# np.mean(X, axis=0)计算数据集X每列的均值,axis=0表示沿着列方向计算。# 然后用原始数据集X减去每列的均值,实现对数据的去均值操作,即让每列数据的均值变为 0 ,最后返回去均值后的数据。return X - np.mean(X, axis=0) # 2. 调用函数,并赋值给X_demean
    X_demean = demean(X)# 3. plt.scatter(X_demean[:, 0], X_demean[:, 1]) 使用matplotlib库的scatter函数绘制散点图,横坐标为去均值后数据X_demean的第一列,纵坐标为第二列。
    plt.scatter(X_demean[:, 0], X_demean[:, 1])
    plt.show()
    

    效果:
    在这里插入图片描述
    验证下均值归零是否正常:

    # 验证下均值归零是否正常
    print(np.mean(X_demean[:, 0])) # 计算第一列均值
    print(np.mean(X_demean[:, 1])) # 计算第二列均值
    

    结果:
    1.1723955140041652e-14 约等于0
    2.5579538487363606e-15 约等于0

  3. 目标函数、梯度上升法等对应公式的代码实现

    # 1. 实现目标函数:找到w,使得方差最大的函数,接受权重向量w和数据集X作为参数
    def f(w, X):return np.sum((X.dot(w)**2)) / len(X)# 2. 求梯度,即目标函数f的解析梯度函数,用于计算梯度。这里通过数学推导得出的梯度公式,X.T.dot(X.dot(w) * 2. / len(X))实现对目标函数求导后的计算,返回梯度向量。
    def df_math(w, X):return X.T.dot(X.dot(w) * 2. / len(X))# 3. 该函数是通过有限差分法近似计算梯度,用于调试和验证df_math函数的正确性。
    #    epsilon是一个很小的数,用于计算数值梯度。通过分别对权重向量w的每个维度加上和减去epsilon,计算对应的函数值差,再除以2 * epsilon来近似该维度上的梯度,最终返回一个近似梯度向量。
    def df_debug(w, X, epsilon=0.0001):res = np.empty(len(w))for i in range(len(w)):w_1 = w.copy()w_1[i] += epsilonw_2 = w.copy()w_2[i] -= epsilonres[i] = (f(w_1, X) - f(w_2, X)) / (2 * epsilon)return res# 4. 该函数用于将输入的向量w进行归一化处理,使其成为单位向量。
    #    np.linalg.norm(w)计算向量w的范数(长度),通过将向量w的每个元素除以其范数,得到方向不变但长度为 1 的单位向量。
    def direction(w):return w / np.linalg.norm(w)# 5. 定义gradient_ascent函数,实现梯度上升算法:
    # def gradient_ascent(df, X, initial_w, eta, n_iters = 1e4, epsilon=1e-8),实现梯度上升算法。参数含义如下:
    # df:计算目标函数梯度的函数。
    # X:数据集。
    # initial_w:初始权重向量。
    # eta:学习率,控制每次权重更新的步长。
    # n_iters:最大迭代次数,默认值为10000(1e4)。
    # epsilon:收敛阈值,默认值为1e-8,用于判断算法是否收敛。
    # w = direction(initial_w),对初始权重向量initial_w进行归一化处理,得到初始的单位权重向量w。
    # cur_iter = 0,初始化当前迭代次数为0。
    # while cur_iter < n_iters:,开始迭代循环,只要当前迭代次数小于最大迭代次数就继续执行:
    # gradient = df(w, X),调用梯度计算函数df,计算当前权重w下的梯度。
    # last_w = w,保存上一次的权重向量。
    # w = w + eta * gradient,根据梯度上升公式更新权重向量,沿着梯度方向移动eta倍的梯度长度。
    # w = direction(w),对更新后的权重向量w再次进行归一化处理,保持其为单位向量。
    # if(abs(f(w, X) - f(last_w, X)) < epsilon): break,计算当前权重和上一次权重对应的目标函数值之差的绝对值,如果小于收敛阈值epsilon,则认为算法收敛,跳出循环。
    # cur_iter += 1,每次迭代结束后,迭代次数加1。
    # return w,循环结束后,返回最终得到的权重向量。
    def gradient_ascent(df, X, initial_w, eta, n_iters = 1e4, epsilon=1e-8):w = direction(initial_w)cur_iter = 0while cur_iter < n_iters:gradient = df(w, X)last_w = ww = w + eta * gradientw = direction(w)if(abs(f(w, X) - f(last_w, X)) < epsilon):breakcur_iter += 1return w
    

    验证代码正确性:

    # 测试梯度上升法求解结果的正确性
    # 初始化权重向量
    # 生成一个长度等于数据特征维度(这里是 2)的随机权重向量。不能用 0 向量开始,可能是因为用 0 向量开始在梯度上升法迭代中会导致一些问题,比如收敛缓慢或无法收敛。
    initial_w = np.random.random(X.shape[1])  # 注意2:不能用0向量开始
    print(initial_w)# 设置梯度上升法中的学习率,控制每次权重更新的步长。
    eta = 0.001# 注意3:不能使用StandardScaler标准化数据
    print(gradient_ascent(df_debug, X_demean, initial_w, eta))
    print(gradient_ascent(df_math, X_demean, initial_w, eta))
    

    结果如下:
    [0.55799828 0.70512732]
    [0.76320173 0.64616029] df_debug函数求得的数据
    [0.76320173 0.64616029] df_math函数求得的数据,和df_debug函数求得的数据是一致的。

  4. 求解第一主成分

    # 调用gradient_ascent函数,传入梯度计算函数df_math、去均值后的数据集X_demean、初始权重向量initial_w和学习率eta,通过梯度上升法计算得到最终的权重向量w。
    w = gradient_ascent(df_math, X_demean, initial_w, eta)# 绘制w向量在二维坐标平面上的图像,这就是我们通过梯度上升法找到的第一个主成分
    plt.scatter(X_demean[:, 0], X_demean[:, 1]) # 横坐标为X_demean的第一列数据,纵坐标为第二列数据
    plt.plot([0, w[0]*30], [0, w[1]*30], color='r') # 由于w是单位向量,对于的数字太小了(1),为了图像好效果明显些,这里分别在横纵坐标轴各自乘以30作为系数
    plt.show()
    

    效果如下:
    在这里插入图片描述

七、求解前n个主成分及PCA在数据预处理中的处理步骤(后续实现)

  1. 数据标准化:首先对原始数据进行标准化处理,将每个特征的均值变为0,方差变为1。这是因为PCA对数据的尺度比较敏感,如果不同特征的尺度差异较大,可能会导致某些特征在协方差计算中占据主导地位,影响主成分的提取效果。均值归零的处理办法:
    • 在进行主成分分析之前,需要对所有样本进行均值归零处理。
    • 均值归零处理通过减去样本整体均值,使样本在每个维度上的均值变为零。
    • 处理后的方差计算公式得到简化,方便后续计算。
  2. 计算协方差矩阵:对标准化后的数据计算协方差矩阵,协方差矩阵能够反映各个特征之间的线性关系。
  3. 特征值分解:对协方差矩阵进行特征值分解,得到特征值和特征向量。
  4. 确定主成分个数:根据具体的应用需求和数据特点,确定需要保留的主成分个数k。常见的方法是根据累计方差贡献率来确定,即选择使得累计方差贡献率达到一定阈值(如80%、90%等)的最小k值。
  5. 构建主成分矩阵:选取前k个最大特征值对应的特征向量,构建一个大小为n×k的主成分矩阵,其中n是原始数据的特征维度。
  6. 数据降维:将原始数据与主成分矩阵相乘,得到降维后的数据。降维后的数据维度为k,且尽可能保留了原始数据的重要信息。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【蓝桥杯—单片机】第十五届省赛真题代码题解析 | 思路整理

第十五届省赛真题代码题解析 前言赛题代码思路笔记竞赛板配置建立模板明确基本要求显示功能部分频率界面正常显示高位熄灭 参数界面基础写法&#xff1a;两个界面分开来写优化写法&#xff1a;两个界面合一起写 时间界面回显界面校准校准过程校准错误显示 DAC输出部分按键功能部…

重邮数字信号处理-实验六用 MATLAB 设计 IIR 数字滤波器

一、实验目的 1、加深对 IIR 数字滤波器设计方法和设计步骤的理解&#xff1b; 2、掌握用模拟滤波器原型设计 IIR 数字滤波器的方法&#xff1b; 3、能编写 MATLAB 函数&#xff0c;掌握设计 IIR 数字滤波器的函数调用方法&#xff1b; 4、根据不同的应用场景&#xff0…

Linux中的基本指令(下)

目录 mv指令 more指令 less指令 head指令 tail 指令 继续理解文件 重定向和追加重定向操作 理解管道 find指令 whereis 指令 bc指令 uname ‒r指令 grep 指令 关机 扩展命令 zip/unzip 指令 tar指令 关于rzsz 系统间的文件互传 接上&#xff01; mv指令 m…

Python文件,模块

一.文件 1.生成一个文件: 2. 提示 : 第二次读时因为之前已经对文件进行了读取操作&#xff0c;文件指针可能已经移动到了文件末尾。在这种情况下&#xff0c;再次调用 read() 方法将不会读取到任何新的内容&#xff0c;因为已经没有未读取的数据了。可以使用 seek() 方法将文…

基于python的升级队列加速决策

a-f大等级是3级 a-c建筑每升1级分别需要8天 d-f建筑每升1级分别需要10天 目前以下建筑队列正在从0级升至1级 建筑A升级需要7天05&#xff1a;16&#xff1a;20 建筑b升级需要06&#xff1a;06&#xff1a;54 建筑c升级需要00&#xff1a;37&#xff1a;00 建筑d升级需要…

编译OpenSSL

OpenSSL简介 OpenSSL是一个用于加密和安全连接的开源软件库。它提供了一系列的加密算法、密码学功能和安全协议的实现&#xff0c;包括SSL&#xff08;Secure Sockets Layer&#xff09;和TLS&#xff08;Transport Layer Security&#xff09;等用于网络安全的协议。OpenSSL可…

Win 转 MacBook Pro 踩坑指南

前言 Window 和 macOS 系统的差异还是很大的&#xff0c;我从 Thinkpad 转用 M1 的 Macbook pro 已经一年了&#xff0c;几乎没有任何不适应&#xff0c;整体感受那是真的牛&#x1f443;&#xff0c;速度和续航惊艳到我了&#xff0c;同时开启 6个 vscode 加几十个浏览器标签…

uniapp uniCloud引发的血案(switchTab: Missing required args: “url“)!!!!!!!!!!

此文章懒得排版了&#xff0c;为了找出这个bug, 星期六的晚上我从9点查到0点多&#xff0c;此时我心中一万个草泥马在崩腾&#xff0c;超级想骂人&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; uniCloud 不想…

数据结构和算法--仅仅用于理解里面的术语,入门级别

数据结构和算法 预先知识&#xff1a;java 黑马前29节 cmd命令&#xff1a; 文件夹路径不区分大小写 E: dir:查看所有文件 cd 目录 :进入 cd… 返回上一级 cd 目录1\目录2 cd\ 回到根目录 cls 清屏 exit 退出 打开文件夹必须用cd 查找&#xff0c;但是文件不用&am…

【设计模式】通过访问者模式实现分离算法与对象结构

概述 定义&#xff1a;封装一些作用于某种数据结构中的各元素的操作(将数据结构于元素进行分离)&#xff0c;它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。 结构 访问者模式包含以下主要角色: 抽象访问者&#xff08;Visitor&#xff09;角色&#xff…

低版本 Linux 系统通过二进制方式升级部署高版本 Docker

​ 一、背景&#xff1a; 在一些 Linux 系统中&#xff0c;由于系统自带的软件源版本较低&#xff0c;或者因网络、权限等限制无法直接通过源文件来升级到最新版本的 Docker。这种情况下&#xff0c;采用二进制方式升级部署高版本 Docker 就成为一种有效的解决方案。下面将详…

SpringAI+Ollama+DeepSeek本地大模型调用

前言 大型语言模型&#xff08;LLM&#xff09;在自然语言处理领域取得了突破性进展&#xff0c;但其庞大的计算资源需求和高昂的调用成本&#xff0c;使得许多开发者望而却步。如何高效、便捷地调用大模型&#xff0c;并将其应用于实际场景&#xff0c;成为了亟待解决的问题。…

【大模型科普】AIGC技术发展与应用实践(一文读懂AIGC)

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈人工智能与大模型应用 ⌋ ⌋ ⌋ 人工智能&#xff08;AI&#xff09;通过算法模拟人类智能&#xff0c;利用机器学习、深度学习等技术驱动医疗、金融等领域的智能化。大模型是千亿参数的深度神经网络&#xff08;如ChatGPT&…

数据结构与算法:归并排序

目录 归并排序的基本思想 归并排序的特性总结 代码 归并排序的非递归版 归并排序的基本思想 归并排序是建立在归并操作上的一种有效的排序算法。改算法是采用分治法的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使每个子序列…

阿里云操作系统控制台评测:国产AI+运维 一站式运维管理平台

阿里云操作系统控制台评测&#xff1a;国产AI运维 一站式运维管理平台 引言 随着云计算技术的飞速发展&#xff0c;企业在云端的运维管理面临更高的要求。阿里云操作系统控制台作为一款集运维管理、智能助手和系统诊断等多功能于一体的工具&#xff0c;正逐步成为企业高效管理…

爬虫案例十三js逆向模拟登录中大网校

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、网站分析二、代码 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; js 逆向模拟登录中大网校 提示&#xff1a;以下是本篇文章正文内…

sql靶场--布尔盲注(第八关)保姆级教程

目录 布尔盲注&#xff08;第八关&#xff09; 1.判断 2.确认布尔盲注 3.手工尝试布尔盲注 表名字符 表数 表名长度 表字符 字段数 字段名长度 字段字符 4.脚本布尔盲注注入 布尔盲注&#xff08;第八关&#xff09; 1.判断 布尔盲注了&#xff0c;这种页面只会有…

【C++入门】变量和基本类型

目录 一、 基本内置类型 1.1. 整型&#xff08;Integer Types&#xff09; 1.2. 浮点型&#xff08;Floating-point Types&#xff09; 1.3. 字符型&#xff08;Character Type&#xff09; 1.4. 布尔型&#xff08;Boolean Type&#xff09; 1.5. 示例代码 二、变量声明…

JVM内存结构笔记03-方法区

文章目录 方法区1.定义2.组成方法区与永久代和元空间的关系为什么要将永久代 (PermGen) 替换为元空间 (MetaSpace) 呢? 3.方法区常用参数4.运行时常量池常量池运行时常量池定义查看class文件 方法区 1.定义 方法区属于是 JVM 运行时数据区域的一块逻辑区域&#xff0c;是各个…

数据库语句

环境变量path下的目录是系统目录。 #include <iostream> #include <mysql.h> #pragma comment(lib,"libmysql.lib")//链接libmysql.dll动态库的中间桥 // MYSQL* conn;//数据库句柄。后面还有网络句柄&#xff08;用来网络收发数据&#xff09; bool co…