主成分分析
主成分分析(princial component analysis
,简称PCA
)是一种无监督的数据降维操作,它通过最大化方差方法来寻找低维空间,能够有效减轻计算量的同时保证处理数据有效性
主要参考文章PCA数学原理,里面做了生动的数学原理分析
相关线性代数、几何学以及统计学数学内容参考:
本文主要内容如下:
- 原理解析
- 如何重建原始数据
- 如何确定\(k\)值
- 操作步骤
numpy
实现
原理解析
- 为什么要进行数据降维?
- 减少内存或磁盘存储
- 加快算法运行
- 数据可视化(将多维数据将为2维或3维,实现数据可视化)
- 为什么能够进行数据降维?
原始数据之间存在结构相关性,某些数据的丢失不影响后续对数据的处理
- 数据降维过程应该注意哪些?
- 保留尽可能多的原始数据内部的结构信息
- 处理后的数据不存在相关性
- 如何保证能够得到尽可能多的原始数据内部的结构信息?
原始数据内部的结构信息不会在投影后重叠在一起,低维空间数据尽可能分散,也即使说投影后每个字段数据的方差越大越好
假设有M
个N
维列向量数据\(X\in R^{N\times M}\),第\(i\)个字段数据的方差计算如下:
\[ Var(X_{,j}) = \frac {1}{M} \sum_{j=1}^{M} (X_{ij} - \mu_{i})^{2} \]
\(\mu_{i}\)表示第\(i\)个字段数据的均值
\[ \mu_{i} = \frac {1}{M} \sum_{j=1}^{M}X_{ij} \]
- 如何保证处理后的数据不存在相关性
投影后不同字段之间的协方差为0
,表示不存在相关性,数据完全独立
第\(i\)个和第\(l\)个字段数据之间的协方差计算如下:
\[ Cov(X_{i}, X_{l}) = \frac {1}{M} \sum_{j=1}^{M} X_{i,j}X_{l,j} \]
- 如何计算方差和协方差?
原始数据\(X\)有\(N\)维,表示有\(N\)个字段,计算字段之间的协方差矩阵\(C\in R^{N\times N}\),对角元素表示方差,非对角元素表示协方差
\[ C = \begin{bmatrix} c_{11} & c_{12} & \cdots & c_{1N}\\ c_{21} & c_{22} & \cdots & c_{2N}\\ \vdots & \vdots & \vdots & \vdots\\ c_{N1} & c_{N2} & \cdots & c_{NN} \end{bmatrix} =\frac {1}{M}XX^{T} \]
其中\(c_{ii}\)表示第\(i\)个字段的随机变量,\(c_{ij}\)表示第\(i\)个和第\(j\)个字段的随机变量
目标是协方差值为0
,也就是协方差矩阵对角化
- 如何计算协方差矩阵对角化?
协方差矩阵\(C\)是实对称矩阵,所以存在正交矩阵\(Q\),能得到
\[ Q^{-1}CQ = Q^{T}CQ = \Lambda = diag(\lambda_{1}, \lambda_{2}, ..., \lambda_{n}) \]
其中\(\lambda_{1}, \lambda_{2}, ..., \lambda_{n}\)为\(C\)的特征值
正交矩阵\(Q\)由特征值对应的特征向量正交化且单位化后组成,\(Q\)的第\(j\)列特征向量对应特征值\(\lambda_{j}\)
所以计算协方差矩阵的特征值和特征向量,将特征值(方差)从大到小排列,取前\(k\)个对应的特征向量(列向量),就是低维空间的基
- 如何执行降维操作?
前\(k\)个特征向量(转置成行向量)组成的矩阵\(P\in R^{k\times N}\),所以
\[ Y = PX \in R^{k\times M} \]
\(Y\)表示数据\(X\)投影到矩阵\(P\)为基的低维空间数据
需不需要数据去量纲?
参考:
需要对原始数据去量纲,也就是让属性成为单纯一个数,去除属性单位带来的影响(比如cm
和kg
)
需要统一单位,所以需要对原始数据进行标准化操作,原始数据减去均值后,再除以各字段的标准差
注意:在图像操作中,每个字段取值均为[0-255]
,可以不进行去量纲操作,减去均值即可
如何重建原始数据
对投影数据进行逆操作
\[ X_{approx} = P^{T}\cdot Y = R^{N\times k}\cdot R^{k\times M} = R^{N\times M} \]
需要每个字段加上均值
\[ (X_{approx})_{i} = (X_{approx})_{i} + \mu_{i} \]
还需要对每个字段乘以字段标准差
\[ (X_{approx})_{i} = (X_{approx})_{i} * \sigma_{i} \]
如何确定\(k\)值
降维目的是保证能够大幅降低维度,同时能够最大限度保持原始数据内部结构信息,通过投影均方误差来评价投影结果
\[ \frac {1}{M} ||X - X_{approx}||^{2} \]
计算投影均方误差和数据集方差(已减去均值)比值,如果要保持99%
方差
\[ \frac {\frac {1}{M} ||X - X_{approx}||^{2}}{\frac {1}{M} ||X||^{2}} \leq 0.01 \]
可以利用特征值来加速计算
\[ 1 - \frac {\sum_{i=1}^{K} \lambda_{i}}{\sum_{i=1}^{N} \lambda_{i}} \leq 0.01 \Rightarrow \frac {\sum_{i=1}^{K} \lambda_{i}}{\sum_{i=1}^{N} \lambda_{i}} \geq 0.99 \]
操作步骤
假设有\(M\)条\(N\)维列向量数据
- 将原始数据按列排成\(N\)行\(M\)列矩阵\(X\in R^{N\times M}\)
- 对\(X\)进行标准化操作(每行减去均值后再除以标准差)
- 求协方差矩阵\(C=\frac {1}{M}XX^{T}\)
- 求协方差矩阵特征值及对应的特征向量
- 将特征向量(行向量形式)按对应特征值大小从上到下排列成矩阵,取前\(k\)行组成矩阵\(P\in R^{k\times N}\)
- \(Y=PX = R^{k\times N}\cdot R^{N\times M}=R^{k\times M}\)即为降维到\(k\)维后的数据
numpy实现
特征值和特征向量计算
函数numpy.linalg.eig用于计算协方差矩阵的特征值和特征向量
numpy.linalg.eig(a)
输入参数\(a\)是方阵
返回两个数组:eigenvalue、eigenvector
1 | w, v = np.linalg.eig(np.diag((1,2,3))) |
函数numpy.linalg.svd用于奇异值分解
numpy.linalg.svd(a, full_matrices=1, compute_uv=1)
- \(a\)是大小为\(M\times N\)的实矩阵或复矩阵
full_matrices
默认为True
,表示返回值\(u\)和\(v\)大小为\(M\times M\)和\(N\times N\);否则形状为\(M\times K\)和\(K\times N\),其中\(K = min(M,N)\)compute_uv
默认为True
,表示是否计算u/v
返回值是3
个数组u/s/v
,其中s
表示特征值并且按从大到小排列,u
表示其对应的特征列向量
1 | >>> X |
scipy.linalg.svd同样实现了奇异值分解
注意:除以标准差时需要注意除数不能为0
pca实现
完整实现代码如下:
1 | # -*- coding: utf-8 -*- |
进行mnist
图像降维,保留99%
的方差,图像从784
维降至43
维
降维(49, 784)
到(49, 43)
耗时0.088249
秒
进行cifar
图像降维,保留99%
的方差,图像从3072
维降至49
维
降维(49, 3072)
到(49, 41)
耗时9.106328秒
小结
PCA是通用的数据降维操作,但在卷积神经网络处理中不推荐使用PCA作为预处理操作,因为在无监督降维过程中,一些关键结构信息会因为方差小而被处理掉