PCA降维

# PCA降维技术 通过上面的特征选择部分,可以选出更好的分析特征,但是如果这些特征维度仍然很高怎么办? 如果数据特征维度太高,首先计算很麻烦,其次增加了问题的复杂程度,分析起来也不方便。这时候就会想是不是再去掉一些特征就好了呢?但是这个特征也不是凭自己的意愿去掉的,因为**盲目减少数据的特征会损失掉数据包含的关键信息,容易产生错误的结论,对分析不利。** 所以想找到一个合理的方式,**既可以减少需要分析的指标,而且又尽可能多的保持原来数据的信息**,PCA就是这个合理的方式之一。 但要注意一点, 特征选择是从已存在的特征中选取携带信息最多的,选完之后的特征依然具有可解释性,而PCA,将已存在的特征压缩,降维完毕后不是原来特征的任何一个,也就是**PCA降维之后的特征我们根本不知道什么含义了。** 如下所示:特征选择 与 特征提取 的区别 ![image.png](https://cos.easydoc.net/17082933/files/ke7v7okk.png) **特征选择**(Feature Selection):choosing a subset of all the features(the ones more informative)。也就是说,特征选择后的特征是原来特征的一个子集。 **特征提取**(Feature Extraction):Creatting a subset of new features by combinations of the exsiting features.也就是说,特征抽取后的新特征是原来特征的一个映射。 PCA就属于特征提取的一种。 ## 1 PCA原理详解 ### 1.1 PCA的概念 PCA(Principal Component Analysis),即主成分分析方法,是一种使用最广泛的数据降维算法。PCA的主要思想是将n维特征映射到k维上,这k维是全新的正交特征也被称为主成分,是在原有n维特征的基础上重新构造出来的k维特征。PCA的工作就是从原始的空间中顺序地找一组相互正交的坐标轴,新的坐标轴的选择与数据本身是密切相关的。其中,**第一个新坐标轴选择是原始数据中方差最大的方向,第二个新坐标轴选取是与第一个坐标轴正交的平面中使得方差最大的,第三个轴是与第1,2个轴正交的平面中方差最大的。依次类推,可以得到n个这样的坐标轴**。通过这种方式获得的新的坐标轴,我们发现,大部分方差都包含在前面k个坐标轴中,后面的坐标轴所含的方差几乎为0。于是,我们可以忽略余下的坐标轴,只保留前面k个含有绝大部分方差的坐标轴。事实上,这相当于只保留包含绝大部分方差的维度特征,而忽略包含方差几乎为0的特征维度,实现对数据特征的降维处理。 思考:我们如何得到这些包含最大差异性的主成分方向呢? 答案:事实上,通过计算数据矩阵的协方差矩阵,然后得到协方差矩阵的特征值特征向量,选择特征值最大(即方差最大)的k个特征所对应的特征向量组成的矩阵。这样就可以将数据矩阵转换到新的空间当中,实现数据特征的降维。 由于得到协方差矩阵的特征值特征向量有两种方法:特征值分解协方差矩阵、奇异值分解协方差矩阵,所以PCA算法有两种实现方法:基于特征值分解协方差矩阵实现PCA算法、基于SVD分解协方差矩阵实现PCA算法。 既然提到协方差矩阵,那么就简单介绍一下方差和协方差的关系。然后概括介绍一下特征值分解矩阵原理、奇异值分解矩阵的原理。概括介绍是因为在我之前的《[机器学习中SVD总结](https://mp.weixin.qq.com/s/Dv51K8JETakIKe5dPBAPVg)》文章中已经详细介绍了特征值分解原理和奇异值分解原理,这里就不再重复讲解了。 ### 1.2 协方差和散度矩阵 样本均值: $\bar{x}=\frac{1}{n} \sum_{i=1}^{N} x_{i}$ 样本方差: $S^{2}=\frac{1}{n-1} \sum_{i=1}^{n}\left(x_{i}-\bar{x}\right)^{2}$ 样本X和样本Y的协方差: $\begin{aligned} {Cov}(X, Y) &=E[(X-E(X))(Y-E(Y))] =\frac{1}{n-1} \sum_{i=1}^{n}\left(x_{i}-\bar{x}\right)\left(y_{i}-\bar{y}\right) \end{aligned}$ 由上面的公式,我们可以得到以下结论: 1) 方差的计算公式是针对一维特征,即针对同一特征不同样本的取值来进行计算得到;而协方差则必须要求至少满足二维特征;方差是协方差的特殊情况。 2) 方差和协方差的除数是n-1,这是为了得到方差和协方差的无偏估计。 协方差为正时,说明X和Y是正相关关系;协方差为负时,说明X和Y是负相关关系;协方差为0时,说明X和Y是相互独立。Cov(X,X)就是X的方差。当样本是n维数据时,它们的协方差实际上是协方差矩阵(对称方阵)。例如,对于3维数据(x,y,z),计算它的协方差就是: ::: hljs-center ${Cov}(X, Y, Z)=\left[\begin{array}{ccc}{Cov}(x, x) & {Cov}(x, y) & {Cov}(x, z) \\ {Cov}(y, x) & {Cov}(y, y) & {Cov}(y, z) \\ {Cov}(z, x) & {Cov}(z, y) & {Cov}(z, z)\end{array}\right]$ ::: 散度矩阵定义为: The scatter matrix is computed by the following equation: $S=\sum_{k=1}^{n}\left({x}_{k}-{m}\right)\left({x}_{k}-{m}\right)^{T}$ where ${m}$ is the mean vector ${m}=\frac{1}{n} \sum_{k=1}^{n} {x}_{k}$ 对于数据X的散度矩阵为$X^TX$。其实协方差矩阵和散度矩阵关系密切,散度矩阵就是协方差矩阵乘以(总数据量-1)。因此它们的特征值和特征向量是一样的。这里值得注意的是,散度矩阵是SVD奇异值分解的一步,因此PCA和SVD是有很大联系。 ### 1.3 **特征值分解矩阵原理** 1) **特征值与特征向量** 如果一个向量v是矩阵A的特征向量,将一定可以表示成下面的形式: $A v=\lambda v$ 其中,λ是特征向量v对应的特征值,一个矩阵的一组特征向量是一组正交向量。 2) **特征值分解矩阵** 对于矩阵A,有一组特征向量v,将这组向量进行正交化单位化,就能得到一组正交单位向量。**特征值分解**,就是将矩阵A分解为如下式: $A=Q \Sigma Q^{-1}$ 其中,Q是矩阵A的特征向量组成的矩阵,$\Sigma$则是一个对角阵,对角线上的元素就是特征值。 ### 1.4 SVD分解矩阵原理 奇异值分解是一个能适用于任意矩阵的一种分解的方法,对于任意矩阵A总是存在一个奇异值分解: 1) 求$AA^T$的特征值和特征向量,用单位化的特征向量构成 $U$。 2) 求$A^TA$的特征值和特征向量,用单位化的特征向量构成 $V$。 3) 将$AA^T$或者$A^TA$的特征值求平方根,然后构成 $Σ$。 ### 1.5 PCA算法两种实现方法 **1.5.1 基于特征值分解协方差矩阵实现PCA算法** >输入:数据集$X=\left\{x_{1}, x_{2}, x_{3}, \ldots, x_{n}\right\}$,需要降到k维。 > >1) 去平均值(即去中心化),即每一位特征减去各自的平均值。、 > >2) 计算协方差矩阵 $\frac{1}{n} X X^{T}$ ,注:这里除或不除样本数量n或n-1,其实对求出的特征向量没有影响。 > >3) 用特征值分解方法求协方差矩阵$\frac{1}{n} X X^{T}$的特征值与特征向量。 > >4) 对特征值从大到小排序,选择其中最大的k个。然后将其对应的k个特征向量分别作为行向量组成特征向量矩阵P。 > >5) 将数据转换到k个特征向量构建的新空间中,即Y=PX。 **总结:** 1) 关于这一部分为什么用$\frac{1}{n} X X^{T}$,这里面含有很复杂的线性代数理论推导,想了解具体细节的可以看下面这篇文章(链接失效)。 2) 关于为什么用特征值分解矩阵,是因为 $\frac{1}{n} X X^{T}$ 是方阵,能很轻松的求出特征值与特征向量。当然,用奇异值分解也可以,是求特征值与特征向量的另一种方法。 **举个例子:** ::: hljs-center $X=\left(\begin{array}{ccccc}-1 & -1 & 0 & 2 & 0 \\ -2 & 0 & 0 & 1 & 1\end{array}\right)$ ::: 以X为例,我们用PCA方法将这两行数据降到一行。 1) **因为X矩阵的每行已经是零均值,所以不需要去平均值。** 2) **求协方差矩阵:** ::: hljs-center $C=\frac{1}{5}\left(\begin{array}{ccccc}-1 & -1 & 0 & 2 & 0 \\ -2 & 0 & 0 & 1 & 1\end{array}\right)\left(\begin{array}{cc}-1 & -2 \\ -1 & 0 \\ 0 & 0 \\ 2 & 1 \\ 0 & 1\end{array}\right)=\left(\begin{array}{cc}\frac{6}{5} & \frac{4}{5} \\ \frac{4}{5} & \frac{6}{5}\end{array}\right)$ ::: 3) **求协方差矩阵的特征值与特征向量。** 求解后的特征值为:$\lambda_{1}=2, \quad \lambda_{2}=\frac{2}{5}$ 对应的特征向量为:$c_{1}\left(\begin{array}{l}1 \\ 1\end{array}\right), c_{2}\left(\begin{array}{c}-1 \\ 1\end{array}\right)$ 其中对应的特征向量分别是一个通解,和可以取任意实数。那么标准化后的特征向量为:$\left(\begin{array}{c}\frac{1}{\sqrt{2}} \\ \frac{1}{\sqrt{2}}\end{array}\right), \quad\left(\begin{array}{c}-\frac{1}{\sqrt{2}} \\ \frac{1}{\sqrt{2}}\end{array}\right)$ 4) **矩阵P为:**$P=\left(\begin{array}{cc}\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\ -\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}}\end{array}\right)$ 5) **最后我们用P的第一行乘以数据矩阵X,就得到了降维后的表示:** ::: hljs-center $Y=\left(\begin{array}{cc}\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}}\end{array}\right)\left(\begin{array}{ccccc}-1 & -1 & 0 & 2 & 0 \\ -2 & 0 & 0 & 1 & 1\end{array}\right)=\left(\begin{array}{ccccc}-\frac{3}{\sqrt{2}} & -\frac{1}{\sqrt{2}} & 0 & \frac{3}{\sqrt{2}} & -\frac{1}{\sqrt{2}}\end{array}\right)$ ::: 结果如图所示: ::: hljs-center ![image.png](https://cos.easydoc.net/17082933/files/ke7w26rz.png) ::: **注意:如果我们通过特征值分解协方差矩阵,那么我们只能得到一个方向的PCA降维。这个方向就是对数据矩阵X从行(或列)方向上压缩降维。** #### 1.5.2 基于SVD分解协方差矩阵实现PCA算法 >输入:数据集$X=\left\{x_{1}, x_{2}, x_{3}, \ldots, 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$ ,则我们可以做如下处理: ::: hljs-center $X_{m * k}^{\prime}=X_{m * n} V_{n * k}^{T}$ ::: 可以得到一个m\*k的矩阵X',这个矩阵和我们原来m\*n的矩阵X相比,列数从n减到了k,可见对列数进行了压缩。也就是说,左奇异矩阵可以用于对行数的压缩;右奇异矩阵可以用于对列(即特征维度)的压缩。这就是我们用SVD分解协方差矩阵实现PCA可以得到两个方向的PCA降维(即行和列两个方向)。 ## 2 PCA实例 **1)PCA的Python实现:** ```PYTHON ##Python实现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], [1, 1], [2, 1], [3, 2]]) print(pca(X,1)) ``` 上面代码实现了对数据X进行特征的降维。结果如下: ![image.png](https://cos.easydoc.net/17082933/files/ke7w9juz.png) **2)用sklearn的PCA与我们的PCA做个比较:** ```PYTHON ##用sklearn的PCA from sklearn.decomposition import PCA import numpy as np X = np.array([[-1, 1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]]) pca=PCA(n_components=1)pca.fit(X) print(pca.transform(X)) ``` 结果如下: ![image.png](https://cos.easydoc.net/17082933/files/ke7waa67.png) **搞了半天结果不是很一样啊!** 分析一下吧! sklearn中的PCA是通过svd_flip函数实现的,sklearn对奇异值分解结果进行了一个处理,因为ui\*σi\*vi=(-ui)\*σi\*(-vi),也就是u和v同时取反得到的结果是一样的,而这会导致通过PCA降维得到不一样的结果(虽然都是正确的)。具体了解可以看参考文章9或者自己分析一下sklearn中关于PCA的源码。 ## 3 PCA的理论推导 PCA有两种通俗易懂的解释:**(1)最大方差理论;(2)最小化降维造成的损失**。这两个思路都能推导出同样的结果。 我在这里只介绍最大方差理论: ::: hljs-center ![image.png](https://cos.easydoc.net/17082933/files/ke7wci5c.png) ::: 在信号处理中认为信号具有较大的方差,噪声有较小的方差,信噪比就是信号与噪声的方差比,越大越好。样本在u1上的投影方差较大,在u2上的投影方差较小,那么可认为u2上的投影是由噪声引起的。 因此我们认为,最好的k维特征是将n维样本点转换为k维后,每一维上的样本方差都很大。 比如我们将下图中的5个点投影到某一维上,这里用一条过原点的直线表示(数据已经中心化): ::: hljs-center ![image.png](https://cos.easydoc.net/17082933/files/ke7wcs69.png) ::: 假设我们选择两条不同的直线做投影,那么左右两条中哪个好呢?根据我们之前的方差最大化理论,左边的好,因为投影后的样本点之间方差最大(也可以说是投影的绝对值之和最大)。 计算投影的方法见下图: ::: hljs-center ![image.png](https://cos.easydoc.net/17082933/files/ke7wd8st.png) ::: 图中,红色点表示样例,蓝色点表示在u上的投影,u是直线的斜率也是直线的方向向量,而且是单位向量。蓝色点是在u上的投影点,离原点的距离是<x,u>(即$X^TU$或者$U^TX$)。 ## 4 选择降维后的维度K(主成分的个数) 如何选择主成分个数K呢?先来定义两个概念: average squared projection error : ::: hljs-center $\frac{1}{m} \sum_{i=1}^{m}\left\|x^{(i)}-x_{a p p r o x}^{(i)}\right\|^{2}$,其中 $=x_{a p p r o x}^{(i)}$为映射值 ::: total variation in the data : ::: hljs-center $\frac{1}{m} \sum_{i=1}^{m}\left\|x^{(i)}\right\|^{2}$ ::: 选择不同的K值,然后用下面的式子不断计算,选取能够满足下列式子条件的最小K值即可。 ::: hljs-center $\frac{\frac{1}{m} \sum_{i=1}^{m}\left\|x^{(i)}-x_{a p p r o x}^{(i)}\right\|^{2}}{\frac{1}{m} \sum_{i=1}^{m}\left\|x^{(i)}\right\|^{2}} \leq t$ ::: 其中t值可以由自己定,比如t值取0.01,则代表了该PCA算法保留了99%的主要信息。当你觉得误差需要更小,你可以把t值设置的更小。上式还可以用SVD分解时产生的S矩阵来表示,如下面的式子: ::: hljs-center $1-\frac{\sum_{i=1}^{k} S_{i i}}{\sum_{i=1}^{n} S_{i i}} \leq t$ ::: --- 转载:[主成分分析(PCA)原理详解](https://blog.csdn.net/program_developer/article/details/80632779)