主成分分析 (PCA) 与其高维度下python实现(简单人脸识别)

时间:2022-09-01 18:02:45

Introduction

  主成分分析(Principal Components Analysis)是一种对特征进行降维的方法。由于观测指标间存在相关性,将导致信息的重叠与低效,我们倾向于用少量的、尽可能多能反映原特征的新特征来替代他们,主成分分析因此产生。主成分分析可以看成是高维空间通过旋转坐标系找到最佳投影(几何上),生成新维度,其中新坐标轴每一个维度都是原维度的线性组合\(\theta'X\)(数学上),满足:

  • 新维度特征之间的相关性尽可能小
  • 参数空间\(\theta\)有界
  • 方差尽可能大,且每个主成分的方差递减

数学表示

  对于样本\(i \in N\) 有\(p\)维特征\(X_{p \times 1}\),于是有\(p\)维主成分\(Z_{1 \times p}\),以及参数空间\(\theta_{p \times p}\)满足:
\[
Z_{p \times 1} = \theta_{p \times p} X_{p \times 1}
\]
  其中\(Z_1 = Z[0]\)便是样本\(i\)的第一主成分值,以此类推。\(\theta\)可以看做是对原坐标系的正交变换,参数估计方法后面会详细讨论。针对上述三点的性质,分别对应有:

  • \(Cov(Z_i,Z_j)=0~~~i,j = 1,2, \cdots,p~and~i \neq j\)
  • \(\sum_{i =1}^{p}{\theta_{ij}^2} = 1~~~j = 1,2,\cdots,p\)
  • \(Var(Z_i) = max(Var(\theta_i X))~and~Var(Z_i)>Var(Z_j)~if~i<j\)

  问题转换为,如何在满足以上性质下找到合适的\(\theta\)

以二维特征为例

主成分分析 (PCA) 与其高维度下python实现(简单人脸识别)
  将原本二维空间以角\(\alpha\)旋转得到新坐标轴,此时在两轴上投影即主成分,我们可以写出此时\(X\)与\(Z\)的关系:
\[
\begin{cases}
Z_1 = cos\alpha X_1 + sin\alpha X_2 \\
Z_2 = -sin\alpha X_1 + cos\alpha X_2
\end{cases}
\]
  参数\(\theta\)可以写成如下矩阵:
\[
\begin{bmatrix}
cos\alpha & sin\alpha \\
-sin\alpha & cos\alpha
\end{bmatrix}
\]
  从上图可以看出,二维平面上点的波动大部分可以归结为\(Z_1\)的波动,小部分可以归结为\(Z_2\)的波动,这样一来,二维问题可以降维至一维,只看\(Z_1\),因为其反应了大部分信息。

Eigenvalue and Eigenvector

矩阵乘法的几何意义

  对于上述示例的向量\(X=\begin{bmatrix} X_1 \\ X_2 \end{bmatrix}\),用参数矩阵\(\theta\)左乘\(X\),即是对向量所在轴进行拉伸变换,而其对角线方向即变换的主要方向,这个方向就是变换后的\(Z_1\)轴,见下图,因此“如果我们想要描述好一个变换,那我们就描述好这个变换主要的变化方向就好了”。
             主成分分析 (PCA) 与其高维度下python实现(简单人脸识别)
        注:*图片来自:http://blog.csdn.net/jinshengtao/article/details/18448355

特征矩阵与特征向量

  如果说一个向量\(v\)是方阵\(A\)的特征向量,那么一定有:
\[
Av=\lambda v
\]
  从这个公式可以看出,特征值所对应的特征向量描绘了此变换的方向,而特征值描绘了此变换的大小,或者说此变换方向对整体方向的贡献值。特征分解满足:
\[
A=Q\Sigma Q^{-1}
\]
  其中A为方阵,Q为特征向量矩阵,每一列均为一个特征向量,\(\Sigma\)为特征值为对角元素的对角阵,与特征向量一一对应。特征值求法如下:
\[
|\lambda E - A|=0 \\\\
(\lambda E - A) X = 0
\]
  其中\(\lambda\)为特征值,带入下式后得到特征值对于的特征向量\(X\),\(E\)为单位阵。

特征值分解与主成分分析有什么关系?

  由主成分性质,求第一主成分\(Z_1 = \theta_1 X\)的问题,即为求\(\theta_1\)使得在\(\theta_1 \theta_1'=1\)下\(Var(Z_1)\)达到最大,其中\(\theta_1\)表示参数矩阵\(\theta\)的第一行,这是条件极值问题,用拉格朗日乘子法求解下式极值:
\[
\begin{eqnarray}
\phi(\theta_1) &=& Var(\theta_1 X)-\lambda ( \theta_1 \theta_1' - 1) \\
&=& \theta_1 \Sigma \theta_1' - \lambda ( \theta_1 \theta_1' - 1)
\end{eqnarray}
\]

  \(\Sigma\) 为随机向量\(X\)的协方差矩阵,对\(\theta_1\)求偏导后得到\(2(\Sigma - \lambda E)\theta_1 = 0\),由于\(\theta_1 \neq 0\),所以转换为求\(|\Sigma-\lambda E |=0\),即求\(\Sigma\)特征值和特征矩阵的问题。

主成分分析简单实例

  设随机向量\(X=(X_1,X_2,X_3)'\)的协方差矩阵\(\Sigma\)如下,对\(X\)进行主成分分析:
\[
\begin{bmatrix}
1 & -2 & 0\\
-2 & 5 & 0 \\
0 & 0 & 2
\end{bmatrix}
\]
  求得\(\Sigma\)的特征值从大到小依次为\(\lambda_1 = 3+\sqrt{8},\lambda_2 = 2,\lambda_3 = 3-\sqrt{8}\),相对应的单位正交($\theta \theta' = E $)特征向量为:
\[
\begin{eqnarray}
\nonumber
\theta_1 &=& [0.383,-0.924,0.000] \\
\nonumber
\theta_2 &= &[0.000,0.000,1.000] \\
\nonumber
\theta_3 &= &[0.924,0.383,0.000]
\end{eqnarray}
\]
  因此,主成分为:

\[
\begin{eqnarray}
\nonumber
Z_1 &=& 0.383 X_1-0.924 X_2 \\
\nonumber
Z_2 &=& X_3 \\
\nonumber
Z_3 &=& 0.924 X_1+0.383 X_2
\end{eqnarray}
\]
  \(Z_1\)对X的贡献率可达\(\frac{3+\sqrt{8}}{3+\sqrt{8}+2+3-\sqrt{8}} = 72.8\%\),而\(Z_2\)的贡献率为25\%,\(Z_1,Z_2\)的联合贡献率为97.85\%,我们可以认为这两个变量以及反映了原变量绝大多数信息,从而实现从三维降到二维的过程。
  

高维数据下的特征值分解

  在现实生活中,由于样本的高维特征(图像识别每一个像素点都是一个维度),将会导致协方差矩阵\(\Sigma\)非常大,计算机难以存储与计算,那如何针对高维数据做特征值分解呢,我们知道\(\Sigma = X X'\),考虑替代矩阵\(P = X' X\),如果有100个样本,10000个维度,那么\(\Sigma\)就是一个10000维方阵,而\(P\)只是一个100维方阵。我们做如下推导:
\[
\begin{eqnarray}
\nonumber
Pv &=& \lambda v\\
\nonumber
X'X v &=& \lambda v\\
\nonumber
X X' X v &=& X \lambda v\\
\nonumber
\Sigma (X v) &=& \lambda (X v)
\nonumber
\end{eqnarray}
\]
  这样通过求\(P\)的特征值和特征向量,其特征值即\(\Sigma\)的特征值,其特征向量右乘随机向量\(X\)即为\(\Sigma\)的特征向量,从而完成高维数据的特征值分解(只能得到部分前几的主成分)。

Algorithm and python programme

计算机特征值分解算法

  计算机在求解方阵的特征值分解时,利用QR分解进行迭代,具体步骤如下:

  1. 将实对称矩阵利用Householder变换法化为三对角矩阵
  2. 用吉文斯变换实现一次等效的QR迭代
  3. 增加迭代次数直至收敛

详情参考文献:
  QR迭代法求解矩阵A的特征值[J],沈欢,北京大学工学院
  C常用算法程序集(第二版)[M],徐士良

聊一聊python的科学计算环境

Python有着非常强大的科学计算库:

  • numpy~~基础计算库,多维数组处理
  • scipy~~基于numpy,用于数值计算等等,默认调用intel mkl(高度优化的数学库)
  • pandas~~强大的数据框,基于numpy
  • matplotlib~~绘图库,基于numpy,scipy
  • sklearn~~机器学习库,有各种机器学习算法

  如果你仅仅装了numpy,那么计算特征值效率极低,5000维要41秒,10000维溢出。但是如果装了numpy+mkl,那么5000维将缩短至0.28秒,10000维1.5秒。mkl包含了blas,~lapack这些效率极高的线性代数库,你也可以尝试配置ATLAS环境(matlab的矩阵运算环境)。
  另外,有一些好用的高度集成的科学计算IDE :Anaconda, ~Canopy

用python实现人脸识别

  下面利用PCA提取如下三幅300*400像素的图片的主成分,由于每张图片有120000个维度,难以进行特征值分解,所以采用上述高维数据的特征分解法:
          主成分分析 (PCA) 与其高维度下python实现(简单人脸识别)
python代码如下:

# -*- coding: utf-8 -*-
import numpy as np
import scipy.linalg as linA # 为了激活线性代数库mkl
from PIL import Image
import os,glob

def sim_distance(train,test):
    '''
    计算欧氏距离相似度
    :param train: 二维训练集
    :param test: 一维测试集
    :return: 该测试集到每一个训练集的欧氏距离
    '''
    return [np.linalg.norm(i - test) for i in train]

picture_path = os.getcwd()+'\\pictures\\'
array_list = []
for name in glob.glob(picture_path+'*.jpg'):
    # 读取每张图片并生成灰度(0-255)的一维序列 1*120000
    img = Image.open(name)
    # img_binary = img.convert('1') 二值化
    img_grey = img.convert('L') # 灰度化
    array_list.append(np.array(img_grey).reshape((1,120000)))

mat = np.vstack((array_list)) # 将上述多个一维序列合并成矩阵 3*120000
P = np.dot(mat,mat.transpose()) # 计算P
v,d = np.linalg.eig(P) # 计算P的特征值和特征向量
d= np.dot(mat.transpose(),d) # 计算Sigma的特征向量 12000 * 3
train = np.dot(d.transpose(),mat.transpose()) # 计算训练集的主成分值 3*3

# 开始测试
test_pic = np.array(Image.open('c.jpg').convert('L')).reshape((1,120000))
result = sim_distance(train.transpose(),np.dot(test_pic,d))
print result
test_pic = np.array(Image.open('e.jpg').convert('L')).reshape((1,120000))
result = sim_distance(train.transpose(),np.dot(test_pic,d))
print result

  计算得到前三特征值为:
\[
\lambda = [412.789,-236.239,-69.550]
\]
  对应的特征矩阵\(\theta_{120000 \times 3}\)为:
\[
\begin{eqnarray}
\nonumber
X_{120000 \times 3}
\begin{bmatrix}
-0.62439 & -0.74493 &0.23495 \\
-0.53146 & 0.18473 &-0.82669 \\
-0.57242 & 0.64105 &0.51125 \\
\end{bmatrix}
\end{eqnarray}
\]
  通过\(\theta'X\)得到三张图片在三个主轴上的值分别为:
\[
\begin{eqnarray}
\nonumber
X_1 = [ -3.7e09,~~ 4.3e08 ,~~ -1.5e08] \\
\nonumber
X_2 = [ -4.9e09 ,~~ 8.2e08, ~~ -1.2e09] \\
\nonumber
X_3 = [ -4.7e09 , ~~ 8.4e08 , ~~-5.8e07]
\end{eqnarray}
\]
  利用如下图片进行识别测试,首先右乘\(\theta'\)得到各自在三个主轴上的值,然后计算出该图片到训练样本中的三张图片的欧式距离:
          主成分分析 (PCA) 与其高维度下python实现(简单人脸识别)
\[
sim_1 = [1.8e08,1.6e09,1.1e09] \\\\
sim_2 = [6.4e08,1.8e09,1.6e09]
\]
  显然,根据计算结果,我们认为左图更像人一点~~O(∩_∩)O,一个简单的利用PCA进行图像识别的小程序就此完成,当然这个非常粗糙,但对于理解PCA有着较大的帮助。

本博原创作品仅供品读,欢迎评论,未经本人同意谢绝转载。特此申明!

主成分分析 (PCA) 与其高维度下python实现(简单人脸识别)的更多相关文章

  1. Python的开源人脸识别库:离线识别率高达99&period;38&percnt;

    Python的开源人脸识别库:离线识别率高达99.38%   github源码:https://github.com/ageitgey/face_recognition#face-recognitio ...

  2. Python的开源人脸识别库:离线识别率高达99&period;38&percnt;(附源码)

    Python的开源人脸识别库:离线识别率高达99.38%(附源码) 转https://cloud.tencent.com/developer/article/1359073   11.11 智慧上云 ...

  3. Python 使用 face&lowbar;recognition 人脸识别

    Python 使用 face_recognition 人脸识别 官方说明:https://face-recognition.readthedocs.io/en/latest/readme.html 人 ...

  4. Python 人工智能之人脸识别 face&lowbar;recognition 模块安装

    Python人工智能之人脸识别face_recognition安装 face_recognition 模块使用系统环境搭建 系统环境 Ubuntu / deepin操作系统 Python 3.6 py ...

  5. python 与 百度人脸识别api

    用python来做人脸识别代码量少 思路清晰, 在使用之前我们需要在我们的配置的编译器中通过pip       install baidu-aip  即可 from aip import AipFac ...

  6. 主成分分析PCA数据降维原理及python应用(葡萄酒案例分析)

    目录 主成分分析(PCA)——以葡萄酒数据集分类为例 1.认识PCA (1)简介 (2)方法步骤 2.提取主成分 3.主成分方差可视化 4.特征变换 5.数据分类结果 6.完整代码 总结: 1.认识P ...

  7. 25 行 Python 代码实现人脸识别——OpenCV 技术教程

    OpenCV OpenCV 是最流行的计算机视觉库,原本用 C 和 C++ 开发,现在也支持 Python. 它使用机器学习算法在图像中搜索人的面部.对于人脸这么复杂的东西,并没有一个简单的检测能对是 ...

  8. 7行Python代码的人脸识别

    随着去年alphago 的震撼表现,AI 再次成为科技公司的宠儿.AI涉及的领域众多,图像识别中的人脸识别是其中一个有趣的分支.百度的BFR,Face++的开放平台,汉王,讯飞等等都提供了人脸识别的A ...

  9. &lbrack;转&rsqb;7行Python代码的人脸识别

    https://blog.csdn.net/wireless_com/article/details/64120516 随着去年alphago 的震撼表现,AI 再次成为科技公司的宠儿.AI涉及的领域 ...

随机推荐

  1. height&colon;100&percnt;与height:inherit的区别

    一.兼容性 首先,inherit这个属性只是在ie8+才支持:100%支持ie6: 二.大多数情况下没有区别 在正常情况下height:100%与height:inherit没有任何区别: 1.父元素 ...

  2. Grunt vs Gulp

    grunt vs gulp 虽然gulp已经出来很久了,但是一直没有去使用过.得益于最近项目需要,就尝试了一下,以下从几个要点讲一下grunt和gulp使用的区别,侧重讲一下在使用gulp过程中发现的 ...

  3. struts开发经验汇总

    笔者接触struts2之时,对于web开发甚至还没有概念,仅有的知识是如何利用HTML.CSS和简单的JS进行静态网页的编写.对于开发一个网站所必需的后台.数据库基本没有了解. 因此这篇博文,可以说不 ...

  4. 初探swift语言的学习笔记七&lpar;swift 的关健词&rpar;

    每一种语言都有相应的关键词,每个关键词都有他独特的作用,来看看swfit中的关键词: 关键词: 用来声明的: “ class, deinit, enum, extension, func, impor ...

  5. DevOps之软件定义网络SDN

    唠叨话 关于德语噢屁事的知识点,仅提供专业性的精华汇总,具体知识点细节,参考教程网址,如需帮助,请留言. <软件定义网络SDN(Software Defined Network)> 关于软 ...

  6. 大数据 --&gt&semi; ProtoBuf的使用和原理

    ProtoBuf的使用和原理 一.简介 Protobuf是一个灵活的.高效的用于序列化数据的协议.相比较XML和JSON格式,protobuf更小.更快.更便捷.Protobuf是跨语言的,并且自带了 ...

  7. poj 3525 凸多边形多大内切圆

    Most Distant Point from the Sea Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4758   ...

  8. BP神经网络综合评价法

    BP神经网络综合评价法是一种交互式的评价方法,一种既能避免人为计取权重的不精确性, 又能避免相关系数求解的复杂性,还能对数量较大且指标更多的实例进行综合评价的方法,它可以根据用户期望的输出不断修改指标 ...

  9. setDaemon 守护线程

    setDaemon(True): 将线程声明为守护线程,必须在start() 方法调用之前设置, 如果不设置为守护线程程序会被无限挂起.这个方法基本和join是相反的. 当我们 在程序运行中,执行一个 ...

  10. 在SELECT的时候&comma;加入一列固定值

    SELECT * FROM (select id id, si_code code, si_sharetype sharetype, si_name name, si_organid organid, ...