简介
最近在3d face
模型生成研究中,经常使用PCA,所以就把PCA的学习记录了下来。主成分分析(PCA, Principal Component Analysis)为我们提供了一种压缩数据的方式,我们也可以将它看作学习数据表示的无监督学习算法。PCA学习一种比原始维度更低的表示,也学习了一种元素之间没有线性相关的表示。我们知道一个经典的无监督学习任务就是找到数据的最佳表示。最佳表示可以是在比本身表示的信息更简单或者更易访问受到一些惩罚火或限制的情况下,尽可能多地保留原始数据的信息。那么PCA就为我们提供了这样一种方法。
PCA算法的概念
PCA(Principal Component Analysis),即主成分分析方法,是一种使用最广泛的数据降维算法。PCA的主要思想是将n维特征映射到k维上,这k维是全新的正交特征也被称为主成分,是在原有n维特征的基础上重新构造出来的k维特征。PCA的工作就是从原始的空间中顺序地找一组相互正交的坐标轴,新的坐标轴的选择与数据本身是密切相关的。其中,第一个新坐标轴选择是原始数据中方差最大的方向,第二个新坐标轴选取是与第一个坐标轴正交的平面中使得方差最大的,第三个轴是与第1,2个轴正交的平面中方差最大的。依次类推,可以得到n个这样的坐标轴。通过这种方式获得的新的坐标轴,我们发现,大部分方差都包含在前面k个坐标轴中,后面的坐标轴所含的方差几乎为0。于是,我们可以忽略余下的坐标轴,只保留前面k个含有绝大部分方差的坐标轴。事实上,这相当于只保留包含绝大部分方差的维度特征,而忽略包含方差几乎为0的特征维度,实现对数据特征的降维处理。
协方差和散度矩阵
基础公式
我们有样本X和样本Y,那么可以得到样本X的均值:
样本X方差:
样本X和样本Y的协方差:
由以上的基础公式我们可以得出以下的结论:
- 方差的计算公式是针对一维特征,即针对同一特征不同样本的取值来进行计算得到;而协方差则必须要求至少满足二维特征;方差是协方差的特殊情况
- 方差和协方差的除数是n-1,这是为了得到方差和协方差的无偏估计
协方差的意义
协方差为正时,说明X和Y是正相关关系;协方差为负时,说明X和Y是负相关关系;协方差为0时,说明X和Y是相互独立,互不相关。Cov(X,X)就是X的方差。当样本是n维数据时,它们的协方差实际上是协方差矩阵(对称方阵)。例如,对于3维数据(x,y,z),计算它的协方差就是:
散度矩阵
对于数据X的散度矩阵为:其实协方差矩阵和散度矩阵关系密切,散度矩阵就是协方差矩阵乘以(总数据量-1)。因此它们的特征值和特征向量是一样的。这里值得注意的是,散度矩阵是SVD奇异值分解的一步,因此PCA和SVD是有很大联系
特征值与SVD分解矩阵原理
特征值与特征向量
如果一个向量v是矩阵A的特征向量,将一定可以表示成下面的形式:其中,λ是特征向量v对应的特征值,一个矩阵的一组特征向量是一组正交向量。
特征值分解矩阵
对于矩阵A,有一组特征向量v,将这组向量进行正交化单位化,就能得到一组正交单位向量。特征值分解,就是将矩阵A分解为如下式:其中,Q是矩阵A的特征向量组成的矩阵,而矩阵Σ则是一个对角阵,对角线上的元素就是特征值。
SVD分解矩阵
奇异值分解是一个能适用于任意矩阵的一种分解的方法,对于任意矩阵A总是存在一个奇异值分解:假设A是一个m*n的矩阵,那么得到的U是一个m*m
的方阵,U里面的正交向量被称为左奇异向量。Σ是一个m*n
的矩阵,Σ除了对角线其它元素都为0,对角线上的元素称为奇异值。 Vt
(t在右上角)是v的转置矩阵,是一个n*n
的矩阵,它里面的正交向量被称为右奇异值向量。而且一般来讲,我们会将Σ上的值按从大到小的顺序排列。
SVD分解矩阵A
- 求AAt的特征值和特征向量,用单位化的特征向量构成 U
- 求AtA的特征值和特征向量,用单位化的特征向量构成 V
- 将AAt或AtA的特征值求平方根,然后构成 Σ
PCA算法两种实现方法
基于特征值分解协方差矩阵实现PCA算法
输入:数据集降到k维
- 去平均值(即去中心化),即每一位特征减去各自的平均值。
-
计算协方差矩阵
注:这里除或不除样本数量n或n-1,其实对求出的特征向量没有影响。
-
用特征值分解方法求协方差矩阵
的特征值与特征向量。
对特征值从大到小排序,选择其中最大的k个。然后将其对应的k个特征向量分别作为行向量组成特征向量矩阵P。
将数据转换到k个特征向量构建的新空间中,即Y=PX
注:为什么使用:
这里面含有很复杂的线性代数理论推导,想了解具体细节的可以看下面这篇文章,CodingLabs - PCA的数学原理
基于SVD分解协方差矩阵实现PCA算法
输入:数据集降到k维
去平均值,即每一位特征减去各自的平均值。
计算协方差矩阵。
通过SVD计算协方差矩阵的特征值与特征向量。
对特征值从大到小排序,选择其中最大的k个。然后将其对应的k个特征向量分别作为列向量组成特征向量矩阵。
将数据转换到k个特征向量构建的新空间中。
,当样本数多、样本特征数也多的时候,这个计算还是很大的。当我们用到SVD分解协方差矩阵的时候,SVD有两个好处:
- 我们的PCA算法可以不用做特征分解而是通过SVD来完成,这个方法在样本量很大的时候很有效。实际上,scikit-learn的PCA算法的背后真正的实现就是用的SVD,而不是特征值分解
- 左奇异矩阵可以用于对行数的压缩;右奇异矩阵可以用于对列(即特征维度)的压缩。这就是我们用SVD分解协方差矩阵实现PCA可以得到两个方向的PCA降维(即行和列两个方向)。
numpy中PCA的使用
实现一个简单的pca
import numpy as np
def pca(X, k): #k is the components you want
#mean of each feature
n_samples, n_features = X.shape
mean=np.array([np.mean(X[:, i]) for i in range(n_features)])
#normalization
norm_X = X - mean
#scatter matrix
scatter_matrix=np.dot(np.transpose(norm_X), norm_X)
#Calculate the eigenvectors and eigenvalues
eig_val, eig_vec = np.linalg.eig(scatter_matrix)
eig_pairs = [(np.abs(eig_val[i]), eig_vec[:,i]) for i in range(n_features)]
# sort eig_vec based on eig_val from highest to lowest
eig_pairs.sort(reverse = True)
# select the top k eig_vec
feature=np.array([ele[1] for ele in eig_pairs[:k]])
#get new data
data=np.dot(norm_X, np.transpose(feature))
return data
X = np.array([[1, 1], [-2, -1], [-3, -2], [3, 1], [2, 1], [3, 2], [3,4], [-3,-1]])
print(pca(X,2))
输出结果如下:sklearn的PCA
from sklearn.decomposition import PCA
import numpy as np
X = np.array([[1, 1], [-2, -1], [-3, -2], [3, 1], [2, 1], [3, 2], [3,4], [-3,-1]])
pca=PCA(n_components=2)
pca.fit(X)
print(pca.transform(X))
结果如下:对照就会发现,结果是不一样的。sklearn中的PCA是通过svd_flip函数实现的,sklearn对奇异值分解结果进行了一个处理,因为ui * σi * vi=(-ui) * σi * (-vi)
,也就是u和v同时取反得到的结果是一样的,而这会导致通过PCA降维得到不一样的结果(虽然都是正确的)。具体了解可以自己分析一下sklearn中关于PCA的源码。
PCA可以做什么
对于PCA可以做什么,对应于不同的业务,有不同的使用场景。
例如我最早接触时,用来分析2D人脸的图片矩阵化后里面的主要成分,提取出关键的维度,使用低维度的矩阵来表示人脸的特征。
当然对应于其他的数据,也是可以使用PCA的,例如在一个向量化好的用户信息矩阵中,需要提取出关键的维度来作为特征描写。所以他的使用场景就类似于他的名字,分析矩阵里面的主要成分,但是维度具体取多少,需要按照自己的数据来计算,也许需要多次的验证。