机器学习——主成分分析(PCA)

目录

背景

引入 

特征维度约减

特征维度约减的概念

为何要维度约减?

维度约减的应用

常规维度约减方法

主成分分析

主成分分析 (PCA)基本思路

主成分的代数定义和代数推导

主成分的代数定义

主成分的代数推导

PCA算法两种实现方法

1、基于特征值分解协方差矩阵实现PCA算法

2、基于SVD分解协方差矩阵实现PCA算法

PCA具体实现

数据集介绍

具体代码实现及运行结果

数据获取

PCA降维

总结


背景

在许多领域的研究与应用中,通常需要对含有多个变量的数据进行观测,收集大量数据后进行分析寻找规律。多变量大数据集无疑会为研究和应用提供丰富的信息,但是也在一定程度上增加了数据采集的工作量。更重要的是在很多情形下,许多变量之间可能存在相关性,从而增加了问题分析的复杂性。如果分别对每个指标进行分析,分析往往是孤立的,不能完全利用数据中的信息,因此盲目减少指标会损失很多有用的信息,从而产生错误的结论。因此需要找到一种合理的方法,在减少需要分析的指标同时,尽量减少原指标包含信息的损失,以达到对所收集数据进行全面分析的目的。由于各变量之间存在一定的相关关系,因此可以考虑将关系紧密的变量变成尽可能少的新变量,使这些新变量是两两不相关的,那么就可以用较少的综合指标分别代表存在于各个变量中的各类信息。主成分分析与因子分析就属于这类降维算法。

引入 

PCA(Principal Component Analysis),即主成分分析方法,是一种使用最广泛的数据降维算法(非监督的机器学习方法)。其最主要的用途在于“降维”,通过析取主成分显出的最大的个别差异,发现更便于人类理解的特征。也可以用来削减回归分析和聚类分析中变量的数目。

特征维度约减

特征维度约减的概念

• 特征约减的目的是将高维特征向量映射到低维子空间中.

• 给定n个样本(每个样本维度为p维){x1,x2,……xn}
通过特征变换/投影矩阵实现特征空间的压缩:

为何要维度约减?

•大多数机器学习算法在高维空间中表现不够鲁棒
–Curse of Dimensionality
–查询速度与精度随着维度增加而降低.
•有价值的维度往往很少
–例如,在基因序列中对于特定疾病有价值的点位十分有限.        

• 可视化: 高位数据在 2D 或 3D空间中的可视化
• 维度约减: 高效的存储与检索
• 噪声消除: 提升分类或识别精度

维度约减的应用

常规维度约减方法

• 无监督方法
– Latent Semantic Indexing (LSI): truncated SVD
– Independent Component Analysis (ICA)
– Principal Component Analysis (PCA)
– Canonical Correlation Analysis (CCA)
• 监督方法
– Linear Discriminant Analysis (LDA)
• 半监督方法
– Research topic

主成分分析

主成分分析 (PCA)基本思路

–通过协方差分析,建立高维空间到低维空间的线性映射/矩阵
–保留尽可能多的样本信息
–压缩后的数据对分类、聚类尽量不产生影响,甚至有所提升

•将原始高维向量通过投影矩阵,投射到低维空间
–这些向量称为主成分 (PCs), 具有无关性、正交的特点。重要的是这些向量的数量要远小于高维空间的维度。

主成分的代数定义和代数推导

主成分的代数定义

给定n个样本(每个样本维度为p维):

定义z_{1j}为样本x_{j}在第一主成分/主方向a1上的投影:

其中

我们的目标是找到a1, 使z1的方差最大。

主成分的代数推导

首先根据z1的方差定义,推导得出:

可以看出,S是维度之间的协方差矩阵,\bar{x}=\frac{1}{n}\sum_{i=1}^{n}x_{i}是样本均值,在实际计算中,可以先将样本减去均值使得\bar{x}=0。

假设\bar{x}=0,根据样本组成的矩阵:

有协方差矩阵:

                                        可证明S半正定!

目标是找到主方向a1,使得z1的方差 a_{1}^{T}Sa_{1}最大化,且满足a_{1}^{T}a_{1}=1,令 λ 为一个 Lagrange 乘子,则有: 

得出a1是协方差矩阵 S 的特征向量。可验证a1对应的特征值,是S的最大特征值。

在a1的基础上,要计算下一个主成分a2,使得z2方差最大化,则有:

根据协方差定义,有:

分别令 λ 与 φ 为 Lagrange 乘子,问题变成最大化:

实际上可以求证a2也是协方差矩阵 S 的特征向量,且a2是S的第二大的特征向量。
以此类推, 可以验证:

• 协方差矩阵S的第k大特征向量对应数据的第k主成分
• 第k大特征向量对应的特征值,为投影到该主成分的方差

PCA算法两种实现方法

1、基于特征值分解协方差矩阵实现PCA算法

输入:数据集 X=\left \{ x_{1} , x_{2} , x_{3} ... x_{n} \right \},需要降到k维。

1、去平均值(即去中心化),即每一位特征减去各自的平均值。

2、计算协方差矩阵 \frac{1}{n}XX^{T},注:这里除或不除样本数量n或n-1,其实对求出的特征向量没有影响。

3、用特征值分解方法求协方差矩阵\frac{1}{n}XX^{T} 的特征值与特征向量。

4、对特征值从大到小排序,选择其中最大的k个。然后将其对应的k个特征向量分别作为行向量组成特征向量矩阵P。

5、将数据转换到k个特征向量构建的新空间中,即Y=PX。

2、基于SVD分解协方差矩阵实现PCA算法

输入:数据集X=\left \{ x_{1} , x_{2} , x_{3} ... x_{n} \right \} ,需要降到k维。

1、去平均值,即每一位特征减去各自的平均值。

2、计算协方差矩阵。

3、通过SVD计算协方差矩阵的特征值与特征向量。

4、对特征值从大到小排序,选择其中最大的k个。然后将其对应的k个特征向量分别作为列向量组成特征向量矩阵。

5、将数据转换到k个特征向量构建的新空间中。

在PCA降维中,我们需要找到样本协方差矩阵 XX^{T} 的最大k个特征向量,然后用这最大的k个特征向量组成的矩阵来做低维投影降维。可以看出,在这个过程中需要先求出协方差矩阵 XX^{T},当样本数多、样本特征数也多的时候,这个计算还是很大的。当我们用到SVD分解协方差矩阵的时候,SVD有两个好处:

1、有一些SVD的实现算法可以先不求出协方差矩阵 XX^{T}也能求出我们的右奇异矩阵V。也就是说,我们的PCA算法可以不用做特征分解而是通过SVD来完成,这个方法在样本量很大的时候很有效。实际上,scikit-learn的PCA算法的背后真正的实现就是用的SVD,而不是特征值分解。

2、注意到PCA仅仅使用了我们SVD的左奇异矩阵,没有使用到右奇异值矩阵,那么右奇异值矩阵有什么用呢?

假设我们的样本是m*n的矩阵X,如果我们通过SVD找到了矩阵 XX^{T}最大的k个特征向量组成的k*n的矩阵 V^{T},则我们可以做如下处理:

X{}'_{m*k}=X{}'_{m*n}V_{n*k}^{T}

可以得到一个m*k的矩阵X',这个矩阵和我们原来m*n的矩阵X相比,列数从n减到了k,可见对列数进行了压缩。也就是说,左奇异矩阵可以用于对行数的压缩;右奇异矩阵可以用于对列(即特征维度)的压缩。这就是我们用SVD分解协方差矩阵实现PCA可以得到两个方向的PCA降维(即行和列两个方向)。

PCA具体实现

数据集介绍

ORL人脸数据集一共包含40个不同人的400张图像,此数据集下包含40个目录,每个目录下有10张图像,每个目录表示一个不同的人。所有的图像是以PGM格式存储,灰度图,图像大小宽度为92,高度为112。

具体代码实现及运行结果

数据获取

代码

%matplotlib inline
# 导入所需模块
import matplotlib.pyplot as plt
import numpy as np
import os
import cv2

# plt显示灰度图片
def plt_show(img):
    plt.imshow(img,cmap='gray')
    plt.show()

# 读取一个文件夹下的所有图片,输入参数是文件名,返回文件地址列表
def read_directory(directory_name):
    faces_addr = []
    for filename in os.listdir(directory_name):
        faces_addr.append(directory_name + "/" + filename)
    return faces_addr

# 读取所有人脸文件夹,保存图像地址在faces列表中
faces = []
for i in range(1,41):
    faces_addr = read_directory('E:/2388412628/FileRecv/Face_Dataset/Face/ORL_Faces/s'+str(i))
    for addr in faces_addr:
        faces.append(addr)


# 读取图片数据,生成列表标签
images = []
labels = []
for index,face in enumerate(faces):
    # enumerate函数可以同时获得索引和值
    image = cv2.imread(face,0)
    images.append(image)
    labels.append(int(index/10+1))


print(len(labels))
print(len(images))
print(type(images[0]))
print(labels)

先读取ORL数据集下的所有图像,同时生成列表标签。下图表示一共有400个标签、400张图像、图像的数据类型以及标签的值。

输出前二十组图片

代码:

# 画出前20组人脸图像
# 创建画布和子图对象
fig, axes = plt.subplots(10,20
                       ,figsize=(20,10)
                       ,subplot_kw = {"xticks":[],"yticks":[]} #不要显示坐标轴
                       )
# 图片x行y列,画布x宽y高
# 填充图像
for i, ax in enumerate(axes.flat):
    ax.imshow(images[i],cmap="gray") #选择色彩的模式

运行结果:

PCA降维

接下来把每张图片数据降到一维,a.flatten()就是把a降到一维,默认是按横的方向降,每张图片的维度是1×10304,与图片的大小92×112=10304相符,将其转换为numpy数组,方便后面的计算。

# 图像数据矩阵转换为一维
image_data = []
for image in images:
    data = image.flatten()
    # a是个矩阵或者数组,a.flatten()就是把a降到一维,默认是按横的方向降
    image_data.append(data)
print(image_data[0].shape)

# 转换为numpy数组
X = np.array(image_data)
y = np.array(labels)
print(type(X))
print(X.shape)

运行结果

接下来导入sklearn的PCA模块,根据标签,使用train_test_split()划分数据集,训练PCA模型,保留100个维度,输出100个特征脸,可以发现越到后面人脸越模糊,意味着所占的比重越小。

代码如下:

# 导入sklearn的pca模块
from sklearn.decomposition import PCA
from sklearn.model_selection import train_test_split

# 画出每个图像数据降到一维后的矩阵
import pandas as pd
data = pd.DataFrame(X)
data.head()

运行结果:

然后划分数据集,训练PCA模型,输出结果

代码如下:

# 划分数据集
x_train,x_test,y_train,y_test = train_test_split(X, y, test_size=0.2) # train训练,test测试

# 训练PCA模型
pca=PCA(n_components=100) # 保留100个纬度
pca.fit(x_train) # 训练过程

# 返回训练集和测试集降维后的数据集
x_train_pca = pca.transform(x_train) # 转换过程
x_test_pca = pca.transform(x_test)
print(x_train_pca.shape) # 320个训练集,保留了100个特征
print(x_test_pca.shape) # 80个测试集,保留了100个特征

V = pca.components_
V.shape
# 100个特征脸
# 创建画布和子图对象
fig, axes = plt.subplots(10,10
                       ,figsize=(15,15)
                       ,subplot_kw = {"xticks":[],"yticks":[]} #不要显示坐标轴
                       )
#填充图像
for i, ax in enumerate(axes.flat):
    ax.imshow(V[i,:].reshape(112,92),cmap="gray") #reshape规定图片的大小,选择色彩的模式

运行结果:

可以看出来,虽然我们把图片的维度从10304维降低到100维,但是我们还是可以看出图片的大致人脸形状,但是数据量就大大的减小了,每张图片降低了10000维度,这对我们数据处理等操作提供了很大的便利。

我们来看看降到100维的图片还保留了原来多少信息

pca.explained_variance_ratio_
# 返回特征所携带的数据是原始数据的多少
pca.explained_variance_ratio_.sum()

运行结果

可以看到,虽然降到了100维但依旧保留了90%的信息,可见PAC的强大之处。

总结

        主成分分析(PCA)是一种常用的多变量数据降维技术,具有广泛的应用领域。本次实验旨在通过PCA方法对数据集进行降维,经过实验,我们发现,通过PCA降维后,仅保留100个维度ORL人脸数据集依旧能保存90%的图片信息,而且还可以大大减少数据存储和处理的复杂度。PCA可以将原始数据降到较低维度,从而提高算法的效率和准确性。在这个实验中,首先读取了所有人脸图片,并将其转换为一维数组。然后使用PCA模型对训练集进行训练,并将训练集和测试集分别进行降维处理。最后,展示了前100个特征脸,并输出了每个新特征向量所占的信息量、特征所携带的数据等信息。

PCA的优点:

  1. 可以减少数据集中的噪声。PCA可以通过降维来去除数据中的噪声,从而提高模型的精度和可靠性。

  2. 可以提高算法的效率。通过降维处理,PCA可以减少特征数量,从而提高算法的效率。

  3. 可以揭示数据背后的本质特征。PCA可以将原始数据转换为新的特征向量,这些特征向量表示数据背后的本质特征,有助于理解数据的本质结构和规律。

PCA的缺点:

  1. 不能处理非线性关系。PCA是一种线性变换方法,无法处理非线性关系的数据。

  2. 容易受到极端值干扰。PCA的计算过程涉及到协方差矩阵的计算,如果数据集中存在极端值,则协方差矩阵可能会失真,从而导致PCA的效果不佳。

  3. 可能会丢失一些重要信息。PCA通常会将数据降维到一个较低的维度,这可能会导致一些重要信息被丢失。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

以太网二层交换机实验

实验目的: (1)理解二层交换机的原理及工作方式; (2)利用交换机组建小型交换式局域网。 实验器材: Cisco packet 实验内容: 本实验可用一台主机去ping另一台主机,并…

GRU算法

前置知识:RNN,LSTM LSTM需要训练的参数很多,极消耗计算资源。GRU是一种LSTM的改进算法,参数更少,更容易训练。 它将忘记门和输入门合并成为一个单一的更新门,同时合并了数据单元状态和隐藏状态&#xff0…

系列二、RestTemplate简介

一、RestTemplate简介 1.1、概述 RestTemplate是一种便捷的访问RestFul服务的模板类,是Spring提供的用于访问Rest服务的客户端模板工具集,它提供了多种便捷访问远程HTTP服务的方法。 1.2、API https://docs.spring.io/spring-framework/docs/5.2.2.REL…

Linux实战:部署基于Postfix 与 Dovecot 的邮件系统

一、电子邮件系统简介 在电子邮件系统中,为用户收发邮件的服务器名为邮件用户代理(Mail User Agent,MUA),MTA (邮件传输代理)的工作职责是转发处理不同电子邮件服务供应商之间的邮件&#xff0…

docker 部署教学版本

文章目录 一、docker使用场景及常用命令1)docker使用场景2)rocky8(centos8)安装 docker3)docker 常用命令补充常用命令 二、 单独部署每个镜像,部署spring 应用镜像推荐(2023-12-18)1、 安装使用 mysql1.1 …

WEB 3D技术 three.js通过光线投射 完成几何体与外界的事件交互

本文 我们来说 光线投射 光线投射技术是用于3维空间场景中的交互事件 我们先编写代码如下 import ./style.css import * as THREE from "three"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";const scene new THRE…

Django Web框架

1、创建PyCharm项目 2、安装框架 pip install django 3、查看安装的包列表 4、使用命令创建django项目 django-admin startproject web 5、目录结构 6、运行 cd web python manage.py runserver7、初始化后台登录的用户名密码 执行数据库迁移生成数据表 python manage.p…

VMware17安装Centos 7.9

1.下载VMware17,下载 VMware Workstation Pro | CN 没有注册码,某多,某宝2元子买一个; 2.下载centos7.9镜像, 3.选择稍后安装操作系统 (如果选择安装程序光盘映像文件,则会按照最小系统自动安装) 4.选择…

华为鸿蒙运行Hello World

前言: 从11月中旬开始通过B站帝心接触鸿蒙,至今一个半月左右不到,从小白到入坑,再到看官网案例,分析案例,了解技术点,还需要理清思路,再写博客,在决定写 <Har…

跟着cherno手搓游戏引擎【3】事件系统和预编译头文件

不多说了直接上代码,课程中的架构讲的比较宽泛,而且有些方法写完之后并未测试。所以先把代码写完。理解其原理,未来使用时候会再此完善此博客。 文件架构: Event.h:核心基类 #pragma once #include"../Core.h" #inclu…

【java爬虫】股票数据获取工具前后端代码

前面我们有好多文章都是在介绍股票数据获取工具,这是一个前后端分离项目 后端技术栈:springboot,sqlite,jdbcTemplate,okhttp 前端技术栈:vue,element-plus,echarts,ax…

WPF+Halcon 培训项目实战 完结(13):HS 鼠标绘制图形

文章目录 前言相关链接项目专栏运行环境匹配图片矩形鼠标绘制Halcon添加右键事件Task封装运行结果个人引用问题原因推测 圆形鼠标绘制代码运行结果 课程完结: 前言 为了更好地去学习WPFHalcon,我决定去报个班学一下。原因无非是想换个工作。相关的教学视…

Redis 与 Spring: 解决序列化异常的探索之旅

🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…

数据结构【线性表篇】(五)

数据结构【线性表篇】(五) 文章目录 数据结构【线性表篇】(五)前言为什么突然想学算法了?为什么选择码蹄集作为刷题软件? 目录一、队列括号匹配(代码用不上,需改成加减乘除应用题) 二、串(一)、串的存储结构(二)、朴素…

异常控制流ECF

大家好,我叫徐锦桐,个人博客地址为www.xujintong.com,github地址为https://github.com/jintongxu。平时记录一下学习计算机过程中获取的知识,还有日常折腾的经验,欢迎大家访问。 一、异常控制流(ECF) 现代…

国科大图像处理2023速通期末——汇总2017-2019

国科大2023.12.28图像处理0854期末重点 图像处理 王伟强 作业 课件 资料 一、填空 一个阴极射线管它的输入与输出满足 s r 2 sr^{2} sr2,这将使得显示系统产生比希望的效果更暗的图像,此时伽马校正通常在信号进入显示器前被进行预处理,令p…

目标检测 YOLOv5 - 推理时的数据增强

目标检测 YOLOv5 - 推理时的数据增强 flyfish 版本 YOLOv5 6.2 参考地址 https://github.com/ultralytics/yolov5/issues/303在训练时可以使用数据增强,在推理阶段也可以使用数据增强 在测试使用数据增强有个名字叫做Test-Time Augmentation (TTA) 实际使用中使…

Ps:亮度蒙版 - 混合颜色带方法

所谓“亮度蒙版”,就是根据图像的明暗程度进行选区并建立蒙版,这样便于对图像上进行分级调色。 Photoshop 支持众多的第三方亮度蒙版插件。如,TKActions、Lumenzia、ADP Pro、Raya Pro、LIM、EasyPanel、Introducing InstaMask等等。如此多的…

python实现平滑线性滤波器——数字图像处理

原理: 平滑线性滤波器是一种在图像处理中广泛使用的工具,主要用于降低图像噪声或模糊细节。这些滤波器的核心原理基于对图像中每个像素及其邻域像素的线性组合。 邻域平均: 平滑线性滤波器通过对目标像素及其周围邻域像素的强度值取平均来工…

【前缀和】【分类讨论】【二分查找】2983:回文串重新排列查询

作者推荐 【动态规划】【字符串】C算法:正则表达式匹配 本文涉及的基础知识点 C算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 二分查找算法合集 回文串重新排列查询 给你一个长度为 偶数 n ,下标从 0 开始的字符…