Python机器学习 -- 主成分分析(PCA)

一、主成分分析

  降维是对数据高维度特征的一种预处理方法。降维是将高维度的数据保留下最重要的一些特征,去除噪声和不重要的特征,从而实现提升数据处理速度的目的。在实际的生产和应用中,降维在一定的信息损失范围内,可以为我们节省大量的时间和成本。降维也成为了应用非常广泛的数据预处理方法。

  降维具有如下一些优点:

    (1)使得数据集更易使用

    (2)降低算法的计算开销

    (3)去除噪声

    (4)使得结果容易理解

  PCA(principal Component Analysis),即主成分分析方法,是一种使用最广泛的数据压缩算法。在PCA中,数据从原来的坐标系转换到新的坐标系,由数据本身决定。转换坐标系时,以方差最大的方向作为坐标轴方向,因为数据的最大方差给出了数据的最重要的信息。第一个新坐标轴选择的是原始数据中方差最大的方法,第二个新坐标轴选择的是与第一个新坐标轴正交且方差次大的方向。重复该过程,重复次数为原始数据的特征维数。

  通过这种方式获得的新的坐标系,我们发现,大部分方差都包含在前面几个坐标轴中,后面的坐标轴所含的方差几乎为0,。于是,我们可以忽略余下的坐标轴,只保留前面的几个含有绝不部分方差的坐标轴。事实上,这样也就相当于只保留包含绝大部分方差的维度特征,而忽略包含方差几乎为0的特征维度,也就实现了对数据特征的降维处理。

二、PCA的推导:基于最大投影方差

       PCA做的事情就是找到这样一组基向量来表示已有的数据点,不仅仅是将高维度数据变成低维度数据,更能够找到最关键信息。

       假设有一组二维数据如图所示:

       假设这个二维空间存在一个一维子空间,只有一个基向量就可以表示,我们怎么确定这个基向量是多少呢?其实直观上,就是把这些数据点投影到哪个向量上面会更好。如果投影到x轴,或者y轴就是选了坐标点,我们发现不是很理想,因为会让有的数据点太接近了不好区分,于是我们考虑如下的向量投影方式,就可以比较好的将这些数据区别开了,如图所示:

       如果采用另外一个基向量表示,就很难区别这些数据点了,说明这个基向量不是一个好的基向量,如图所示:

       因为方差是衡量随机变量的离散程度的统计方法,因此求随机变量的离散程度,就是求所有的随机变量投影到某个向量上的方差;

       假设一个数据集\bg_white X\bg_white n个样本,每个样本有\bg_white m个特征形成的 \bg_white n*m 的矩阵:

                                                                   \large X=\begin{bmatrix} x_{11} & x_{12} & \cdots & x_{1m} \\ x_{21} & x_{22} &\cdots &x_{2m} \\ \vdots & \vdots & \cdots & \vdots \\ x_{n1}& x_{n2} & \cdots & x_{nm} \end{bmatrix}

       对所有样本进行中心化,即每一位特征减去各自的平均值

       假设某个单位向量\bg_white W是一个\bg_white m*1 的矩阵:

                                                                       \large \bg_white \large W=\begin{bmatrix} w_{1}\\ w_{2}\\ \vdots \\ w_{m} \end{bmatrix}\:\:\:\:\:\:\:s.t.(W^{T} W=1)

       把所有的随机变量投影到某个单位向量\bg_white W上,得到 \bg_white n*1 的矩阵 Z

                                                                       \large \bg_white \large Z=XW=\begin{bmatrix} z_{1}\\ z_{2}\\ \vdots \\ z_{n} \end{bmatrix}

       直接用 Z 去求方差\dpi{100} Var,使得方差最大所对应的\bg_white W就是最好的投影方向,这个方向就是主方向;

       求 Z 的平均值 \overline{Z}

                                                                              \large \overline{Z}=\frac{1}{n}\sum_{i=1}^{n}z_{i}

       求 Z 的方差\bg_white \dpi{100} Var\left ( Z \right )

                                                                \large Var\left ( Z \right )=\frac{1}{n}\sum_{i=1}^{n}\left ( z_{i}-\overline{Z} \right )^{2}

       假设Z是已经中心化过的数据,即\overline{Z}=0,可以得到\bg_white \dpi{100} Var\left ( Z \right )

                                                               \large Var\left ( Z \right )=\frac{1}{n}\sum_{i=1}^{n} z_{i}^{2}

       由矩阵点乘的概念可以得到:

                                                              \large Var\left ( Z \right )=\frac{1}{n}\sum_{i=1}^{n} z_{i}^{2}=Z^{T}\cdot Z

       又因为Z=XW,所以可以得到:

                                                              \large Var\left ( W \right )=\left ( XW \right )^{T}\cdot \left ( XW \right )

       由上式可知道,若有一个方向\bg_white W可以使得\bg_white W的方差最大,方向\bg_white W就是主方向;

       带约束条件下的极值问题,就可以用拉格朗日乘子法,即:

                                                      \large \begin{align*} L\left ( W,\lambda \right )&= \left ( XW \right )^{T}\cdot \left ( XW \right )-\lambda \left ( W^{T}W-1 \right )\\& = W^{T}X^{T}\cdot XW - \lambda W^{T}W-\lambda \end{align*}

       因为X是一个对称矩阵,则对于W^{T}X^{T}\cdot XW的求导是:

                                                            \large \begin{align*} \frac{\delta (W^{T}X^{T}\cdot XW)}{\delta W}&=\frac{\delta [(XW)^{T}\cdot XW]}{\delta W}\\&=2\frac{\delta (X\cdot W)^{T}}{\delta W} X\cdot W\\&=2X^{T}XW \end{align*}

       由上式得,在极值处,L\left ( W,\lambda \right ) 的偏导等于0,即

                                                                \large \frac{\delta L}{\delta W}=2X^{T}XW-2\lambda W=0

       根据上式,可以得到:

                                                                               \large X^{T}XW=\lambda W

       从上面可以看出,\bg_white WX^{T}X\bg_white m^{'}个特征向量组成的矩阵,而\bg_white \lambdaX^{T}X的特征值。当我们将数据集从\bg_white m维降到\bg_white m^{'}维时,需要找到最大的\bg_white m^{'}个特征值对应的特征向量。这\bg_white m^{'}个特征向量组成的矩阵\bg_white W即为我们需要的矩阵。对于原始数据集,我们只需要用z_{i}=W^Tx_{i},就可以把原始数据集降维到最小投影距离的\bg_white m^{'}维数据集。

三、 PCA实例

       下面举一个简单的例子,说明PCA的过程。

       假设我们的数据集有10个二维数据\bg_white X,需要用PCA降到1维特征。

                                                                                           X=\begin{bmatrix} 2.5&2.4 \\ 0.5&0.7 \\ 22.2& 2.9\\ 1.9&2.2 \\ 3.1&3.0 \\ 2.3&2.7 \\ 2.0&1.6 \\ 1.0&1.1 \\ 1.5&1.6 \\ 1.1&0.9 \end{bmatrix}

       首先我们对样本中心化,这里样本的均值为(1.81, 1.91),所有的样本减去这个均值后,即中心化后的数据集为:

                                                                                     X=\begin{bmatrix} 0.69 &0.49 \\ -1.31&-1.21\\ 0.39&0.99 \\ 0.09& 0.29\\ 1.29&1.09 \\ 0.49&0.79 \\ 0.19&-0.31 \\ - 0.81&-0.81 \\ -0.31&-0.31 \\ -0.71 & -1.01 \end{bmatrix}

       现在我们开始求样本的协方差矩阵,由于我们是二维的,则协方差矩阵为:

                                                               \large \mathbf{XX^T} = \left( \begin{array}{ccc} cov(x_1,x_1) & cov(x_1,x_2)\\ cov(x_2,x_1) & cov(x_2,x_2) \end{array} \right)

       对于我们的数据,求出协方差矩阵为:

                                                              \large \mathbf{XX^T} = \left( \begin{array}{ccc} 0.616555556 & 0.615444444\\ 0.615444444 & 0.716555556 \end{array} \right)

       求出特征值为(0.490833989, 1.28402771),对应的特征向量分别为:

                            \large (0.735178656, 0.677873399)^T\;\; (-0.677873399, -0.735178656)^T

       由于最大的k=1个特征值为1.28402771,对于的k=1个特征向量为:

                                                           \large (-0.677873399, -0.735178656)^T

       则我们的W为:

                                                           \large (-0.677873399, -0.735178656)^T

       我们对所有的数据集进行投影 z_{i}=W^Tx_{i},得到PCA降维后的10个一维数据集为:

                                                           \large W^{'}=\begin{bmatrix} -0.827970186\\ 1.77758033\\ -0.992197494\\ -0.274210416\\ -1.67580142\\ -0.91249103\\ 0.0991094375\\ 1.14457216\\ 0.438046137\\ 1.22382056 \end{bmatrix}

四、代码实现

  PCA 操作流程

  输入:\bg_white m维样本集X=\left ( x_{1} ,x_{2},...,x_{n}\right ),要降维到的维数\bg_white m^{'}

  输出:降维后的样本集X^{'}

    1.对所有的样本进行中心化(去平均值):

                                                 \large x_{i} = x_{i} - \frac{1}{m}\sum\limits_{j=1}^{m} x_{j}\:\:\:\:\:\:\:\:\:\: i\in \left ( 1,2,...,n \right )

    2.计算协方差矩阵X^{T}X

    3.计算协方差矩阵X^{T}X的特征值\bg_white \lambda与特征向量\bg_white W

    4.对特征值\bg_white \lambda从大到小排序;

    5.保留最大的个特征向量\bg_white \lambda

    6.将数据转换到特征向量构建的新空间中;

#导入numpy库
from numpy import *

#解析文本数据函数
#@filename 文件名txt
#@delim 每一行不同特征数据之间的分隔方式,默认是tab键'\t'
def loadDataSet(filename,delim='\t')
    #打开文本文件
    fr=open(filename)
    #对文本中每一行的特征分隔开来,存入列表中,作为列表的某一行
    #行中的每一列对应各个分隔开的特征
    stringArr=[line.strip().split(delim) for line in fr.readlines()]
    #利用map()函数,将列表中每一行的数据值映射为float型
    datArr=[map(float.line)for line in stringArr]
    #将float型数据值的列表转化为矩阵返回
    return mat(datArr)

#pca特征维度压缩函数
#@dataMat 数据集矩阵
#@topNfeat 需要保留的特征维度,即要压缩成的维度数,默认4096    
def pca(dataMat,topNfeat=4096):
    #求数据矩阵每一列的均值
    meanVals=mean(dataMat,axis=0)
    #数据矩阵每一列特征减去该列的特征均值
    meanRemoved=dataMat-meanVals
    #计算协方差矩阵,除数n-1是为了得到协方差的无偏估计
    #cov(X,0) = cov(X) 除数是n-1(n为样本个数)
    #cov(X,1) 除数是n
    covMat=cov(meanRemoved,rowvar=0)
    #计算协方差矩阵的特征值及对应的特征向量
    #均保存在相应的矩阵中
    eigVals,eigVects=linalg.eig(mat(conMat))
    #sort():对特征值矩阵排序(由小到大)
    #argsort():对特征值矩阵进行由小到大排序,返回对应排序后的索引
    eigValInd=argsort(eigVals)
    #从排序后的矩阵最后一个开始自下而上选取最大的N个特征值,返回其对应的索引
    eigValInd=eigValInd[:-(topNfeat+1):-1]
    #将特征值最大的N个特征值对应索引的特征向量提取出来,组成压缩矩阵
    redEigVects=eigVects[:,eigValInd]
    #将去除均值后的数据矩阵*压缩矩阵,转换到新的空间,使维度降低为N
    lowDDataMat=meanRemoved*redEigVects
    #利用降维后的矩阵反构出原数据矩阵(用作测试,可跟未压缩的原矩阵比对)
    reconMat=(lowDDataMat*redEigVects.T)+meanVals
    #返回压缩后的数据矩阵即该矩阵反构出原始数据矩阵
    return lowDDataMat,reconMat

  上述降维过程,首先根据数据矩阵的协方差的特征值和特征向量,得到最大的\bg_white m^{'}个特征值对应的特征向量组成的矩阵,可以称之为压缩矩阵;得到了压缩矩阵之后,将去平均值的数据矩阵乘以压缩矩阵,就实现了将原始数据特征转化为新的空间特征,进而使数据特征得到了压缩处理。

  当然,我们也可以根据压缩矩阵和特征均值,反构得到原始数据矩阵,通过这样的方式可以用于调试和验证。

  下图是通过matplotlib将原始数据点(三角形点)和第一主成分点(圆形点)绘制出来的结果。显然,第一主成分点占据着数据最重要的信息。

import matplotlib
import matplotlib.pyplot as plt
fig=plt.figure()
ax=fig.add_subplot(lll)
#三角形表示原始数据点
ax.scatter(dataMat[:,0].flatten().A[0],dataMat[:,1].flatten().A[0],\
                    marker='^',s=90)
#圆形点表示第一主成分点,点颜色为红色
ax.scatter(reconMat[:,0].flatten().A[0],reconMat[:,1].flatten().A[0]\, marker='o',s=90,c='red')

五、PCA算法总结

  这里对PCA算法做一个总结。作为一个非监督学习的降维方法,它只需要特征值分解,就可以对数据进行压缩,去噪。因此在实际场景应用很广泛。为了克服PCA的一些缺点,出现了很多PCA的变种,比如第六节的为解决非线性降维的KPCA,还有解决内存限制的增量PCA方法Incremental PCA,以及解决稀疏数据降维的PCA方法Sparse PCA等。

  PCA算法的主要优点有:

    1)仅仅需要以方差衡量信息量,不受数据集以外的因素影响。 

    2)各主成分之间正交,可消除原始数据成分间的相互影响的因素。

    3)计算方法简单,主要运算是特征值分解,易于实现。

  PCA算法的主要缺点有:

    1)主成分各个特征维度的含义具有一定的模糊性,不如原始样本特征的解释性强。

    2)方差小的非主成分也可能含有对样本差异的重要信息,因降维丢弃可能对后续数据处理有影响。

猜你喜欢

转载自blog.csdn.net/qq_38328378/article/details/81387449