一、引言
其实对于我们来讲,学习机器学习的目的就是为了解决实际生活中所存在的问题。但是事实上我们在运行书上的程序时能够得到较好的结果,是作者有意为之,这些数据集并非最初就是“最合心意”的。真实的训练数据总是存在各种各样的问题:
1、 比如我们分析一场汽车比赛的数据时,有两项特征分别是“平均每小时公里数km/min”和“平均速度m/s”,显然这两项特征只需要取一项就可以了,另一项属于多余信息。
2、 现在某手机厂商需要我们根据市场销售情况预测他们接下来一款手机会不会大火,但是他所提供的特征的其中几项是:销售价格、屏幕大小、CPU运算速度。而我们都知道手机的销售价格与屏幕大小和CPU的好坏都有很大关系,那我们就即不能独立的考虑也不能将其合并。
3、 对于许多有着大量特征却样本数很少的数据集而言,若依次训练后的结果很容易过拟合。
为了解决上述问题,在此提出一种解决方案——降维。降维是对数据高维度特征的一种预处理方法。降维是将高维度的数据保留下最重要的一些特征,去除噪声和不重要的特征,从而实现提升数据处理速度的目的。在实际的生产和应用中,降维在一定的信息损失范围内,可以为我们节省大量的时间和成本。降维也成为了应用非常广泛的数据预处理方法。
二、降维的方法
目前降维的方法主要有三种,分别是:主成分分析、因子分析和独立成分分析。其中主成分分析(PCA)的应用最为广泛,也是我们这次重点关注的对象。但是仍然要对其他两项有一定的了解。
PCA是Principal component analysis的缩写,中文翻译为主元分析。它是一种对数据进行分析的技术,最重要的应用是对原有数据进行简化。正如它的名字:主元分析,这种方法可以有效的找出数据中最“主要”的元素和结构,去除噪音和冗余,将原有的复杂数据降维,揭示隐藏在复杂数据背后的简单结构。它的优点是简单,而且无参数限制,可以方便的应用与各个场合
因子分析(Factor Analysis)是指研究从变量群中提取共性因子的统计技术,这里的共性因子指的是不同变量之间内在的隐藏因子。例如,一个学生的英语、数据、语文成绩都很好,那么潜在的共性因子可能是智力水平高。因此,因子分析的过程其实是寻找共性因子和个性因子并得到最优解释的过程。
独立成分分析(ICA)是一种主元分解的方法。其基本思想是从一组混合的观测信号中分离出独立信号。比如在一个大房间里,很多人同时在说话,样本是这个房间里各个位置的一段录音,ICA可以从这些混合的录音中分离出每个人独立的说话的声音。ICA认为观测信号是若干个统计独立的分量的线性组合,ICA要做的是一个解混过程。
三、PCA理论分析
PCA将数据投射到一个低维子空间实现降维。例如,二维数据集降维就是把点投射成一条线,数据集的每个样本都可以用一个值表示,不需要两个值。三维数据集可以降成二维,就是把变量映射成一个平面。一般情况下,n维数据集可以通过映射降成k维子空间,其中k≤n。
在PCA中,数据从原来的坐标系转换到新的坐标系,由数据本身决定。转换坐标系时,以方差最大的方向作为坐标轴方向,因为数据的最大方差给出了数据的最重要的信息。第一个新坐标轴选择的是原始数据中方差最大的方法,第二个新坐标轴选择的是与第一个新坐标轴正交且方差次大的方向。重复该过程,重复次数为原始数据的特征维数。不断重复这个过程直到找到n个主成分。
通过这种方式获得的新的坐标系,我们发现,大部分方差都包含在前面几个坐标轴中,后面的坐标轴所含的方差几乎为0。于是,我们可以忽略余下的坐标轴,只保留前面的几个含有绝不部分方差的坐标轴。事实上,这样也就相当于只保留包含绝大部分方差的维度特征,而忽略包含方差几乎为0的特征维度,也就实现了对数据特征的降维处理。
那我们究竟应该如何确定包含最大差异性的主成分方向呢?我们可以通过计算数据矩阵的协方差矩阵,然后得到协方差矩阵的特征值及特征向量,选择特征值最大(也即包含方差最大)的N个特征所对应的特征向量组成的矩阵,我们就可以将数据矩阵转换到新的空间当中,实现数据特征的降维(N维)。
协方差矩阵:
等价的,如果将,写成行向量的形式:
我们就可以将协方差就可以表示成:
那么,对于一组具有m个观测变量,n个采样时间点的采样数据X,将每个观测变量的值写为行向量,可以得到一个m*n的矩阵:
根据协方差矩阵的定义,我们可以推导出:
Cx是一个 的平方对称矩阵。 对角线上的元素是对应的观测变量的方差。非对角线上的元素是对应的观测变量之间的协方差。协方差矩阵Cx包含了所有观测变量之间的相关性度量。更重要的是,这些相关性度量反映了数据的噪音和冗余的程度。
在对角线上的元素越大,表明信号越强,变量的重要性越高;元素越小则表明可能是存在的噪音或是次要变量。
在非对角线上的元素大小则对应于相关观测变量对之间冗余程度的大小。
一般情况下,初始数据的协方差矩阵总是不太好的,表现为信噪比不高且变量间相关度大。PCA的目标就是通过基变换对协方差矩阵进行优化,找到相关“主元”。
在线形代数中,PCA问题可以描述成以下形式:
寻找一组正交基组成的矩阵P,有Y=PX,使得是对角阵。则P的行向量(也就是一组正交基),就是数据X的主元向量。
对Cx进行推导:
定义,则是一个对称阵。对进行对角化求取特征向量得:
则D是一个对角阵,而E则是对称阵的特征向量排成的矩阵。求出特征向量矩阵后我们取,则,由线形代数可知矩阵P有性质,从而进行如下计算:
可知此时P的就是我们需要求得变换基。X的主元即是的特征向量,也就是矩阵P的行向量。矩阵Cy对角线上第i个元素是数据X在方向Pi的方差。
我们可以得到PCA求解的一般步骤:
1)采集数据形成m*n的矩阵。m为观测变量个数,n为采样点个数。
2)在每个观测变量(矩阵行向量)上减去该观测变量的平均值得到矩阵X。
3)对进行特征分解,求取特征向量以及所对应的特征根。
四、PCA算法实现
算法步骤: 输入数据集D={x1,x2,x3,x4,....xm},低维空间维数 n(xi表示数据的第i维,m表示数据维度为m,n表示最终要变换的维度)
操作:1.对所有样本进行中心化,(对每个维度减去这个维度的数据均值)
2.计算样本的协方差矩阵
3.对协方差矩阵做特征值分解
4.选取前n个最大的特征值对应的的特征向量构成特征向量矩阵W 输出:Wm*n*Dh*m = D′(一个m*n的矩阵乘以数据集h*m的矩阵得到h*n的矩阵D′)D′就是降维后的数据集h*m->h*n(m<n)
使用python代码实现:
from numpy import *
import matplotlib.pyplot as plt
# 加载数据
def loadDataSet(filename,delim = '\t'):
fr = open(filename)
stringArr = [line.strip().split(delim) for line in fr.readlines()]
dataArr = [map(float,line) for line in stringArr]
print(mean(mat(dataArr)))
return mat(dataArr)
def pca(dataMat,topN=999999):
# 形成样本矩阵,样本中心化
meanVals= mean(dataMat,axis=0)
meanRemoved = dataMat - meanVals
# 计算样本矩阵的协方差矩阵
covMat = cov(meanRemoved,rowvar=0)
# 对协方差矩阵进行特征值分解,选取最大的 p 个特征值对应的特征向量组成投影矩阵
eigVals,eigVects = linalg.eig(mat(covMat))
#sort():对特征值矩阵排序(由小到大)
#argsort():对特征值矩阵进行由小到大排序,返回对应排序后的索引
eigValInd = argsort(eigVals)
#从排序后的矩阵最后一个开始自下而上选取最大的N个特征值,返回其对应的索引
eigValInd = eigValInd[:-(topN+1):-1]
redEigVects = eigVects[:,eigValInd]
# 对原始样本矩阵进行投影,得到降维后的新样本矩阵
lowDDataMat = meanRemoved * redEigVects
reconMat = (lowDDataMat * redEigVects.T)+meanVals
return lowDDataMat,reconMat
上述降维过程,首先根据数据矩阵的协方差的特征值和特征向量,得到最大的N个特征值对应的特征向量组成的矩阵,可以称之为压缩矩阵;得到了压缩矩阵之后,将去均值的数据矩阵乘以压缩矩阵,就实现了将原始数据特征转化为新的空间特征,进而使数据特征得到了压缩处理。我们使用书上所提供的数据进行测试,将文本“textSet.txt”导入到程序中。测试代码如下:
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')
下图是通过matplotlib将原始数据点(三角形点)和第一主成分点(圆形点)绘制出来的结果。显然,第一主成分点占据着数据最重要的信息。
六、示例:利用PCA对半导体制造数据降维
我们知道,像集成电路这样的半导体,成本非常昂贵。如果能在制造过程中尽早和尽快地检测出是否出现瑕疵,将可能为企业节省大量的成本和时间。那么,我们在面对大规模和高维度数据集时,显然计算损耗会很大,无疑会非常耗时。所以,如果利用PCA等降维技术将高维的数据特征进行降维处理,保留那些最重要的数据特征,舍弃那些可以忽略的特征,将大大加快我们的数据处理速度和计算损耗,为企业节省不小的时间和成本。
数据集中可能会包含很多缺失值,这些缺失值是以NaN进行标识的。那么如何对待这些缺失值呢?如果存在大量的样本存在缺失值,显然选择将这些有缺失值得样本丢弃不可取;此外,由于并不知道这些值的意义,选择将缺失值替换为0也不是一个很好的决定。所以,这里我们选择将数据集中的特征缺失值,用数据集中该维度所有非NaN特征的均值进行替换。相比之下,采用均值替换的方法在这里是一个相对较好的选择。
#缺失值处理函数
def replaceNaNWithMean():
#解析数据
datMat=loadDataSet('secom.data',' ')
#获取特征维度
numFeat=shape(datMat)[1]
#遍历数据集每一个维度
for i in range(numFeat):
#利用该维度所有非NaN特征求取均值
meanVal=mean(datMat[nonzero(~isnan(datMat[:,i].A))[0],i])
#将该维度中所有NaN特征全部用均值替换
datMat[nonzero(isnan(datMat[:,i].A))[0],i]=meanVal
return datMat
那么我们如果确定需要保留哪些重要特征呢?PCA函数可以给出数据所包含的信息量,然后通过定量的计算数据中所包含的信息决定出保留特征的比例。代码实现:
dataMat=pca.replaceNanWithMean()#将NaN替换为平均值
meanVals=mean(dataMat,axis=0)
meanRemoved=dataMat-meanVals #去除均值
conMat=cov(meanRemoved,rowvar=0) #计算协方差矩阵
eigVals,eigVects=linalg.eig(mat(covMat)) #对矩阵进行特征值分析
观察特征值结果:
我们可以看到这些特征值中很大一部分是零,这代表这些特征都是其他特征的副本,即为冗余,降维从就是一个减弱甚至去除噪音和冗余的过程。我们无法精确知道所需要的主成分数目,必须通过在实验中取不同的值来确定。有效的主成分数目则取决于数据集和具体应用。 上述分析能够得到所用到的主成分数目,然后我们可以将该数目输入到PCA算法中,最后得到约简后数据就可以在分类器中使用了。
七、总结
PCA技术的一大好处是对数据进行降维的处理。我们可以对新求出的“主元”向量的重要性进行排序,根据需要取前面最重要的部分,将后面的维数省去,可以达到降维从而简化模型或是对数据进行压缩的效果。同时最大程度的保持了原有数据的信息。
参考内容:
[1] Lindsay I Smith. (2002) “A tutorial onPrincipal Components Analysis”
[2] JonathonShlens. (2005) “A Tutorial on Principal Component Analysis”
[3] Peter Harrington 《机器学习与实战》 中国邮电出版社