PCA(Principal Components Analysis)主成分分析是一个简单的机器学习算法,利用正交变换把由线性相关变量表示的观测数据转换为由少量线性无关比变量表示的数据,实现降维的同时尽量减少精度的损失,线性无关的变量称为主成分。大致流程如下:

  首先对给定数据集(数据是向量)进行规范化,使得数据集的平均值为0,方差为1(规范化是为了使数据散布在原点附近,而不是远离原点的某块区域,便于后面的计算)。之后对每个数据进行正交变换,把数据投影到几个少量的相互正交的方向(这些方向构成了数据空间的一个子空间)上。数据在每个方向上都有对应的坐标,而用这些方向和对应的坐标(坐标×方向的累加)就能近似表示原来高维的数据。因此这些方向的求解就是PCA的关键,这些方向有如下性质:

  如果再由这些坐标通过对应的方向映射回原来的数据,精度损失是同等方向数量的方向集合(或者叫同维度的子空间吧)中最小的,而数据集在各个方向上的坐标的方差之和是同等方向数量的方向集合中最大的,也正对应着方差越大表示这个方向上保存数据的信息量越大(方差越小所有数据越集中在一个点上信息量当然越小)。数据集在这些方向的上的坐标的方差,从大到小排序,就把这每一个方向称为第一主成分、第二主成分……

主成分推导

  接下来推导什么样的方向是主成分,即什么样的方向集合能保存原数据集更多的信息。下面把数据映射为各个方向上的坐标称为编码(即降维),再反映射回来称为解码。

  定义矩阵$X\in R^{m\times n}$为数据集,由$m$个$n$维行向量数据$\{x_1,x_2,...,x_m\}$组成。首先求得数据均值与方差(以下是按元素进行的运算):

$\displaystyle\overline{x}=\sum\limits_{i=1}^{m}\frac{x_i}{m}$

$\displaystyle s=\frac{1}{m-1} \sum\limits_{i=1}^{m}\left(x_i-\overline{x}\right)^2 $

  然后规范化样本:

$\displaystyle x_i^\ast = \frac{x_i-\overline{x}}{\sqrt{s}}, i=1,2,\ldots,m$

  获得规范化后的数据集$X^*$。随后PCA将把$X^*$编码成矩阵$Y^*\in R^{m\times k},k<n$,通过右乘列向量单位正交的方向矩阵$D\in R^{n\times k}$得到编码后的矩阵$Y^*$:

$Y^* = X^*\cdot D$

  而再解码回来是再乘上$D^T$:

$\hat{X^*} = Y^*\cdot D^{T}$

  因为矩阵$D$并不可逆,所以编码是不可逆的,也就是说解码并不能完全恢复回$X^*$。为了最小化精度损失,容易想到,优化$D$来最小化$\hat{X^*}$与$X^*$之差的Frobenius范数:

$ \begin{aligned} &D = \displaystyle\text{arg}\min\limits_D{||\hat{X^*} - X^*||^2_F}\\ &D = \text{arg}\min\limits_D{|| X^*DD^T - X^*||^2_F}\\ &D = \text{arg}\min\limits_D{\text{Tr}[(X^*DD^T - X^*)^T(X^*DD^T - X^*)]}\\ &D = \text{arg}\min\limits_D{\text{Tr}[DD^TX^{*T}X^*DD^T-DD^TX^{*T}X^*-X^{*T}X^*DD^T+X^{*T}X^*]}\\ \end{aligned} $

  去掉与$D$不相关的$X^{*T}X^*$项,再由迹的性质,矩阵乘法循环右移迹的值不变:

$ \begin{aligned} &D = \text{arg}\min\limits_D{\text{Tr}[X^*DD^TDD^TX^{*T}-X^*DD^TX^{*T}-D^TX^{*T}X^*D]}\\ &D = \text{arg}\min\limits_D{\text{Tr}[X^*DD^TX^{*T}-X^*DD^TX^{*T}-D^TX^{*T}X^*D]}\\ &D = \text{arg}\max\limits_D{\text{Tr}[D^TX^{*T}X^*D]}\\ \end{aligned} $

  容易发现当$D$的列向量取$X^{*T}X^*$的前$k$大特征值对应的特征向量时,有这个迹的值最大,等于前$k$大特征值之和,且此时压缩的精度损失最少。

性质

  经过上面的推导,我们可以发现,$X^{*T}X^*$实际上就是$X$行向量每个元素之间的协方差矩阵$\Sigma_x$(没有除以$m-1$)。定义$\lambda_1,\lambda_2,...,\lambda_n$为$\Sigma_x$从大到小排列的特征值。我们可以推出下面两个性质。

  性质一、编码得到的矩阵$Y^*\in R^{m\times k}$的行向量各个元素对应的协方差矩阵$\displaystyle\Sigma_y = \text{diag}(\lambda_1,\lambda_2,...,\lambda_k)$ 。

  性质二、如果不进行压缩,即编码矩阵形如$D\in R^{n\times n}$,从而$Y^*\in R^{m\times n}$,那么$Y^*$的行向量各个元素方差之和等于$X^*$($X$也一样)的行向量各个元素方差之和,也就是:

$\displaystyle\sum\limits_{i=1}^n \Sigma_{y_{ii}}= \sum\limits_{i=1}^n \Sigma_{x_{ii}} = \sum\limits_{i=1}^n (X^{*T}X^*)_{ii}$

  首先证明性质一。

  由之前的定义,$X^*$是$X$经过行标准化后的矩阵,所以对$X^*$的任意列进行求和有

$\displaystyle\sum\limits_{i=1}^mX^*_{ij}=0,\;\;j=1,2,...,n$

  而对于$Y^*=X^*D$,对$Y^*$的任意列进行求和有

$ \begin{aligned} \sum\limits_{i=1}^m Y^*_{ij} &= \sum\limits_{i=1}^mX^*_{i:}D_{:j} = \sum\limits_{i=1}^m\sum\limits_{k=1}^nX^*_{ik}D_{kj}\\ &= \sum\limits_{k=1}^nD_{kj}\sum\limits_{i=1}^mX^*_{ik}= 0,\;\;j=1,2,...,k \end{aligned} $

  每列求和都为0,说明,$Y^*$行向量每个元素的均值都为0,无需再计算行向量的均值进行标准化。因此,可以直接计算$Y^*$的协方差矩阵:

$ \begin{aligned} \Sigma_y = Y^{*T}Y^* = D^TX^{*T}X^*D=\text{diag}(\lambda_1,\lambda_2,...,\lambda_k) \end{aligned} $

  有性质一以后,性质二就容易了:

  如果不进行压缩,由性质一可得,$Y^*$行向量各元素方差之和就是$X^{*T}X^*$的特征值之和,矩阵特征值之和又等于矩阵的迹,而$X^{*T}X^*$的迹就是$X^*$行向量各个元素的方差之和。所以得到性质二。

  另外,映射矩阵$D$的列向量在人脸识别中就是所谓的特征脸(PCA+SVM实现人脸识别)。

手动代码实现

  实验代码:

import matplotlib.pyplot as plt
import pylab #原本在jupyter里才能显示的图片,可以用窗口显示
import numpy as np def PCA_img(img,n):
t = np.mean(img,0) #以行向量为压缩单元,求行平均
s = np.std(img,0) #求行标准差
img=(img-t)/s #每行减去平均值进行规范化
v,vectors = np.linalg.eig(np.dot(img.T,img)/(len(img)-1)) #生成规范化矩阵后,转置乘自身再除以(行数-1),即为行向量各个元素的协方差矩阵,求协方差矩阵的特征值与特征向量
indv = v.argsort() #将特征值排序,从小到大
vectors = vectors[:,indv] #将特征向量按特征值大小排序
vectors = vectors[:,-n:] #选择前n大特征值对应的特征向量,作为映射矩阵。在人脸识别中就是特征脸
img = np.dot(np.dot(img,vectors),vectors.T) #规范化矩阵先乘映射矩阵再乘映射矩阵的转置,也就是先压缩再解压缩
img = np.multiply(img,s)+t #把减掉的均值加回去变为原矩阵
return img img=plt.imread("aaa.jpg") #读取图片 img.flags["WRITEABLE"] = True
img = img.astype(float)
n = 50
img[:,:,0] = PCA_img(img[:,:,0],n)
img[:,:,1] = PCA_img(img[:,:,1],n)
img[:,:,2] = PCA_img(img[:,:,2],n)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(img/255)
print(img)
pylab.show()

  原图是1200×1920的图:

  压缩为1200×50后再解压回去:

sklearn包PCA

  sklearn中计算PCA比直接使用numpy矩阵计算快得多,这是因为它里面实现了比较高效的随机算法,虽然每次算出来的值不一样,但是相差不大。代码如下:

import sklearn.decomposition as dc 

pca = dc.PCA(n_components = 10)       #规定PCA要取前k大特征值对应的特征向量的个数,即要映射到几维,PCA默认压缩行,比如100*100压缩到100*10
pca.fit(A) #将要用于压缩的矩阵传入,用来“学习”压缩矩阵
D = pca.components_ #获取“学习”到的编码矩阵(压缩矩阵)D。原矩阵A经过AD^T会得到压缩后的矩阵(这里的D是上面推算的D^T)
C = pca.transform(B) #传入新的矩阵B,用“学习”到的编码矩阵进行压缩,即BD^T。在人脸特征提取中,同一个人的不同人脸照片,用同一个压缩矩阵压缩后的坐标向量通常相似,因此可以用于人脸识别的降维

PCA——主成分分析的更多相关文章

  1. 用PCA(主成分分析法)进行信号滤波

    用PCA(主成分分析法)进行信号滤波 此文章从我之前的C博客上导入,代码什么的可以参考matlab官方帮助文档 现在网上大多是通过PCA对数据进行降维,其实PCA还有一个用处就是可以进行信号滤波.网上 ...

  2. 机器学习之PCA主成分分析

    前言            以下内容是个人学习之后的感悟,转载请注明出处~ 简介 在用统计分析方法研究多变量的课题时,变量个数太多就会增加课题的复杂性.人们自然希望变量个数较少而得到的 信息较多.在很 ...

  3. PCA主成分分析Python实现

    作者:拾毅者 出处:http://blog.csdn.net/Dream_angel_Z/article/details/50760130 Github源代码:https://github.com/c ...

  4. 机器学习 - 算法 - PCA 主成分分析

    PCA 主成分分析 原理概述 用途 - 降维中最常用的手段 目标 - 提取最有价值的信息( 基于方差 ) 问题 - 降维后的数据的意义 ? 所需数学基础概念 向量的表示 基变换 协方差矩阵 协方差 优 ...

  5. PCA(主成分分析)方法浅析

    PCA(主成分分析)方法浅析 降维.数据压缩 找到数据中最重要的方向:方差最大的方向,也就是样本间差距最显著的方向 在与第一个正交的超平面上找最合适的第二个方向 PCA算法流程 上图第一步描述不正确, ...

  6. PCA主成分分析(上)

    PCA主成分分析 PCA目的 最大可分性(最大投影方差) 投影 优化目标 关键点 推导 为什么要找最大特征值对应的特征向量呢? 之前看3DMM的论文的看到其用了PCA的方法,一开始以为自己对于PCA已 ...

  7. PCA主成分分析方法

    PCA: Principal Components Analysis,主成分分析. 1.引入 在对任何训练集进行分类和回归处理之前,我们首先都需要提取原始数据的特征,然后将提取出的特征数据输入到相应的 ...

  8. 【建模应用】PCA主成分分析原理详解

    原文载于此:http://blog.csdn.net/zhongkelee/article/details/44064401 一.PCA简介 1. 相关背景 上完陈恩红老师的<机器学习与知识发现 ...

  9. PCA主成分分析+白化

    参考链接:http://deeplearning.stanford.edu/wiki/index.php/%E4%B8%BB%E6%88%90%E5%88%86%E5%88%86%E6%9E%90 h ...

  10. CS229 6.6 Neurons Networks PCA主成分分析

    主成分分析(PCA)是一种经典的降维算法,基于基变换,数据原来位于标准坐标基下,将其投影到前k个最大特征值对应的特征向量所组成的基上,使得数据在新基各个维度有最大的方差,且在新基的各个维度上数据是不相 ...

随机推荐

  1. 2015ACM/ICPC亚洲区沈阳站-重现赛 M - Meeting (特殊建边,最短路)

    题意:有\(n\)个点,\(m\)个集合,集合\(E_i\)中的点都与集合中的其它点有一条边权为\(t_i\)的边,现在问第\(1\)个点和第\(n\)个点到某个点的路径最短,输出最短路径和目标点,如 ...

  2. Linux系统编程【2】——编写who命令

    学到的知识点 通过实现who命令,学到了: 1.使用man命令寻找相关信息 2.基于文件编程 3.体会到c库函数与系统调用的不同 4.加深对缓冲技术的理解 who命令的作用 who命令的使用 在控制终 ...

  3. JSR-303 实现参数校验

    参考 1. 什么是JSR-303 JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation,官方参考实现是Hibernate Validator. 此实现与 Hib ...

  4. VUE 3.0 初体验之路

    在2020年9月中旬,vue.js发布了3.0正式版,在不久的将来,VUE3.0 也终将成为大前端的必然趋势, 环境搭建 node 版本要求: Node.js8.9 或更高版本 ,输入 node -v ...

  5. Nginx 四层负载均衡

    目录 四层负载均衡概述 配置七层负载均衡 配置四层负载均衡 四层负载均衡概述 四层负载均衡是基于IP+端口的负载均衡,七层负载均衡是基于URL或主机名等应用层信息的负载均衡. 其他层负载均衡(转载): ...

  6. Linux-单用户/救援模式

    目录 企业案例一:忘记root密码 企业案例二:修改了默认的运行级别为poweroff或者reboot 企业案例三:误损坏MBR(只能以救援模式解决) 企业案例四:误删除GRUB菜单(只能以救援模式解 ...

  7. 查找命令中grep,find,which和whereis的使用及区别

    在linux系统中,许多时候需要查找某些文件或者字符,如果用ls, cd 等基础命令就显得很无力了,那么Linux提供了grep,find,which 三种查找命令,在这里我记录一下: 一.grep命 ...

  8. mysql(四)------Mysql中的锁

    1. 2 MySQL InnoDB 锁的基本类型 https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html 官网把锁分成了 8 类.所以我 ...

  9. 015.NET5_MVC_Razor局部视图

    局部视图 1. 可以增加代码的重用性 如何定义? 1.添加一cshtml文件 2. 在页面中调用局部视图:@html.Partial("局部视图的名称") 问题:局部视图中不能访问 ...

  10. vue-cli-service & @vue/cli-service

    vue-cli-service & @vue/cli-service https://www.npmjs.com/package/@vue/cli-service https://yarnpk ...