一、主成分分析
降维是对数据高维度特征的一种预处理方法。降维是将高维度的数据保留下最重要的一些特征,去除噪声和不重要的特征,从而实现提升数据处理速度的目的。在实际的生产和应用中,降维在一定的信息损失范围内,可以为我们节省大量的时间和成本。降维也成为了应用非常广泛的数据预处理方法。
降维具有如下一些优点:
(1)使得数据集更易使用
(2)降低算法的计算开销
(3)去除噪声
(4)使得结果容易理解
PCA(principal Component Analysis),即主成分分析方法,是一种使用最广泛的数据压缩算法。在PCA中,数据从原来的坐标系转换到新的坐标系,由数据本身决定。转换坐标系时,以方差最大的方向作为坐标轴方向,因为数据的最大方差给出了数据的最重要的信息。第一个新坐标轴选择的是原始数据中方差最大的方法,第二个新坐标轴选择的是与第一个新坐标轴正交且方差次大的方向。重复该过程,重复次数为原始数据的特征维数。
通过这种方式获得的新的坐标系,我们发现,大部分方差都包含在前面几个坐标轴中,后面的坐标轴所含的方差几乎为0,。于是,我们可以忽略余下的坐标轴,只保留前面的几个含有绝不部分方差的坐标轴。事实上,这样也就相当于只保留包含绝大部分方差的维度特征,而忽略包含方差几乎为0的特征维度,也就实现了对数据特征的降维处理。
二、PCA的推导:基于最大投影方差
PCA做的事情就是找到这样一组基向量来表示已有的数据点,不仅仅是将高维度数据变成低维度数据,更能够找到最关键信息。
假设有一组二维数据如图所示:
假设这个二维空间存在一个一维子空间,只有一个基向量就可以表示,我们怎么确定这个基向量是多少呢?其实直观上,就是把这些数据点投影到哪个向量上面会更好。如果投影到x轴,或者y轴就是选了坐标点,我们发现不是很理想,因为会让有的数据点太接近了不好区分,于是我们考虑如下的向量投影方式,就可以比较好的将这些数据区别开了,如图所示:
如果采用另外一个基向量表示,就很难区别这些数据点了,说明这个基向量不是一个好的基向量,如图所示:
因为方差是衡量随机变量的离散程度的统计方法,因此求随机变量的离散程度,就是求所有的随机变量投影到某个向量上的方差;
假设一个数据集有个样本,每个样本有个特征形成的 的矩阵:
对所有样本进行中心化,即每一位特征减去各自的平均值
假设某个单位向量是一个 的矩阵:
把所有的随机变量投影到某个单位向量上,得到 的矩阵 :
直接用 去求方差,使得方差最大所对应的就是最好的投影方向,这个方向就是主方向;
求 的平均值 :
求 的方差:
假设是已经中心化过的数据,即,可以得到:
由矩阵点乘的概念可以得到:
又因为,所以可以得到:
由上式可知道,若有一个方向可以使得的方差最大,方向就是主方向;
带约束条件下的极值问题,就可以用拉格朗日乘子法,即:
因为X是一个对称矩阵,则对于的求导是:
由上式得,在极值处, 的偏导等于0,即
根据上式,可以得到:
从上面可以看出,为的个特征向量组成的矩阵,而为的特征值。当我们将数据集从维降到维时,需要找到最大的个特征值对应的特征向量。这个特征向量组成的矩阵即为我们需要的矩阵。对于原始数据集,我们只需要用,就可以把原始数据集降维到最小投影距离的维数据集。
三、 PCA实例
下面举一个简单的例子,说明PCA的过程。
假设我们的数据集有10个二维数据,需要用PCA降到1维特征。
首先我们对样本中心化,这里样本的均值为(1.81, 1.91),所有的样本减去这个均值后,即中心化后的数据集为:
现在我们开始求样本的协方差矩阵,由于我们是二维的,则协方差矩阵为:
对于我们的数据,求出协方差矩阵为:
求出特征值为(0.490833989, 1.28402771),对应的特征向量分别为:
由于最大的k=1个特征值为1.28402771,对于的k=1个特征向量为:
则我们的W为:
我们对所有的数据集进行投影 ,得到PCA降维后的10个一维数据集为:
四、代码实现
PCA 操作流程
输入:维样本集,要降维到的维数;
输出:降维后的样本集;
1.对所有的样本进行中心化(去平均值):
2.计算协方差矩阵;
3.计算协方差矩阵的特征值与特征向量;
4.对特征值从大到小排序;
5.保留最大的个特征向量;
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
上述降维过程,首先根据数据矩阵的协方差的特征值和特征向量,得到最大的个特征值对应的特征向量组成的矩阵,可以称之为压缩矩阵;得到了压缩矩阵之后,将去平均值的数据矩阵乘以压缩矩阵,就实现了将原始数据特征转化为新的空间特征,进而使数据特征得到了压缩处理。
当然,我们也可以根据压缩矩阵和特征均值,反构得到原始数据矩阵,通过这样的方式可以用于调试和验证。
下图是通过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)方差小的非主成分也可能含有对样本差异的重要信息,因降维丢弃可能对后续数据处理有影响。