机器学习实战(十一)利用PCA来简化数据
第十三章 利用PCA来简化数据
13.1 降维技术
数据降维的原因:
1)可以使数据显示更加容易
2)使得数据集更容易使用
3)降低算法计算开销
4)去除噪声
5)使得结果易懂
降维主要有三种方法,依次介绍如下。
13.1.1 主成分分析(PrincipalComponentAnalysis,PCA)
在 PCA中,数据从原来的坐标系转换到了新的坐标系,新坐标系的选择是由数据本身决定的。第一个新坐标轴选择的是原始数据中方差最大的方向,第二个新坐标轴的选择和第一个坐标轴正交且具有最大方差的方向。该过程一直重复,重复次数为原始数据中特征的数目。我们会发现,大部分方差都包含在最前面的几个新坐标轴中。因此,我们可以忽略余下的坐标轴,即对数据进行了降维处理。
13.1.2 因子分析(Factor Analysis)
在因子分析中,我们假设在观察数据的生成 中 有一 些观察 不 到的隐 变量 ( latentvariable )。假设观察数据是这些隐变量和某些噪声的线性组合 。那么隐变量的数据可能比观察数据的数目少,也就是说通过找到隐变量就可以实现数据的降维。
13.1.3 独立成分分析(Independent Component Analysis, ICA)
ICA假设数据是从 N 个数据源生成的,这一点和因子分析有些类似。 假设数据为多个数据源的混合观察结果,这些数据源之间在统计上是相互独立的,而在 ? 0 人中只假设数据是不相关的。同因子分析一样,如果数据源的数目少于观察数据的数目,则可以实现降维过程。
PCA应用最为广泛,下面来介绍PCA。
13.2 PCA
13.2.1 移动坐标轴和降维
第一步:坐标轴旋转
图13-1中的大量数据点,则B是覆盖最多的线条。PCA中,我们对数据的坐标进行了旋转,该旋转过程取决于数据本身。
第一条坐标轴:旋转到覆盖数据的最大方差位置(也就是覆盖数据最大差异性的坐标轴),即图中的直线B,数据的最大方差给出了数据的最重要的信息。
第二条坐标轴:选择与第一条坐标轴垂直的坐标轴,也就是正交坐标轴(覆盖数据次打差异性的坐标轴)。
利用PCA,我们将数据坐标轴旋转至数据角度上的那些重要的方向。
坐标轴旋转并未减少数据的维度
第二步:降维
如上图,其中包含着 3 个不同的类别。要区分这 3 个 类 别 ,可以使用决策树。我们还记得决策树每次都是基于一个特征来做决策的。我 们会发现,在 x轴上可以找到一些值,这些值能够很好地将这 3 个类别分开。这 样 ,我们就可能得到一些规则,比 如 当 0 < 4 ) 时 ,数据属于类别 0 。如果使用 SVM这样稍微复杂一点的分类器,我们就会得到更好的分类面和分类规则,比如当(w0 * x + w1 * y + b) > 0 时 ,数据也属于类别 0 。 SVM可能比决策树得到更好的分类间隔,但是分类超平面却很难解释。
通过PCA进行降维处理,我们就可以同时获得 SVM和决策树的优点:
1)一 方 面 ,得到了和决策树一样简单的分类器,同时分类间隔和 SVM一样好,如上图,其中的数据来自于上面的图并经 过PCA转换之后绘制而成的,如果仅使用原始数据,那么这里的间隔会比决策树的间隔更大。
2) 另 外 ,由于只需要考虑一维信息,因此数据就可以通过比 S V M 简单得多的很容易采用的规则进行区分 。
在上图中,我们只需要一维信息即可,因为另一维信息只是对分类缺乏贡献的噪声数据,在二位平面下,这一点看上去微不足道,但是如果在高维空间下则意义重大。
PCA实现:
第一个主成分:数据差异性最大(即方差最大)的方向
第二个主成分:数据差异性的次大(与第一个主成分方向正交)的方向
如何求取主成分的值:
数据集的协方差阵及其特征值分析
如何转化到特征空间:
得到协方差矩阵的特征向量,就可以保留最大的N个值,这些特征向量也给出了B个最重要特征的真实结构,我们可以通过将数据乘上这N个特征向量而将其转换到新的空间。
13.2.2 统计学基本概念
1)均值:
2)标准差:
3)方差:
4)协方差:
标准差和方差一般是用来描述一维数据的,但现实生活中常常遇到含有多维数据的数据集,协方差就是用来度量两个随机变量关系的统计量。
可以通俗的理解为:两个变量在变化过程中是同方向变化?还是反方向变化?同向或反向程度如何?
你变大,同时我也变大,说明两个变量是同向变化的,这时协方差就是正的。
你变大,同时我变小,说明两个变量是反向变化的,这时协方差就是负的。
从数值来看,协方差的数值越大,两个变量同向程度也就越大。反之亦然。
公式:
性质:
意义:如果有X,Y两个变量,每个时刻的“X值与其均值之差”乘以“Y值与其均值之差”得到一个乘积,再对这每时刻的乘积求和并求出均值(其实是求“期望”,但就不引申太多新概念了,简单认为就是求均值了)。
13.2.3 在Numpy中实现PCA
将数据转换为前N个主成分的伪代码如下:
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))
eigValInd = argsort(eigVals)
eigValInd = eigValInd[:-(topN+1):-1]
redEigVects = eigVects[:,eigValInd]
# 对原始样本矩阵进行投影,得到降维后的新样本矩阵
lowDDataMat = meanRemoved * redEigVects
reconMat = (lowDDataMat * redEigVects.T)+meanVals
return lowDDataMat,reconMat
if __name__=='__main__':
dataMat = mat(loadtxt('testSet.txt'))
lowMat,reconMat = pca(dataMat,1)
fig = plt.figure()
ax = fig.add_subplot(111)
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=50,c='red')
plt.show()
书中代码运行有误
相比书中的修改:dataMat = mat(loadtxt('testSet.txt'))
结果:
上图显示了原始数据集和第一主成分
13.3 实例:利用PCA降维技术对半导*造数据降维
缺失值处理:取平均值代替缺失值,平均值根据非NaN得到。
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]
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))
eigValInd = argsort(eigVals)
eigValInd = eigValInd[:-(topN+1):-1]
redEigVects = eigVects[:,eigValInd]
# 对原始样本矩阵进行投影,得到降维后的新样本矩阵
lowDDataMat = meanRemoved * redEigVects
reconMat = (lowDDataMat * redEigVects.T)+meanVals
return lowDDataMat,reconMat
def replaceNanWithMean():
datMat = loadDataSet('secom.data', ' ')
numFeat = shape(datMat)[1]
for i in range(numFeat):
meanVal = mean(datMat[nonzero(~isnan(datMat[:,i].A))[0],i]) #values that are not NaN (a number)
datMat[nonzero(isnan(datMat[:,i].A))[0],i] = meanVal #set NaN values to mean
return datMat
if __name__=='__main__':
#加载数据
dataMat = replaceNanWithMean()
#去除均值
meanVals = mean(dataMat, axis=0)
meanRemoved = dataMat - meanVals
#计算协方差
covMat = cov(meanRemoved, rowvar=0)
#特征值分析
eigVals, eigVects = linalg.eig(mat(covMat))
print (eigVals)
结果:
结果说明:
我们会发现其中很多值都是 0吗?实 际 上 ,其中有超过 2 0 % 的特征值都是 0 。这就意味着这些特征都是其他特征的副本,也就是 说 ,它们可以通过其他特征来表示,而本身并没有提供额外的信息。
接 下 来 ,我们了解一下部分数值的数量级。最 前 面 15 个 值的 数量 级 大 于 105 ,实际上那以后 的 值 都 变 得 非 常 小 。这 就相 当 于 告 诉 我 们 只 有 部 分 重 要 特 征 ,重要特征的数目也很快就会下 降 。
最 后 ,我们可能会注意到有一些小的负值,它们主要源自数值误差应该四舍五入成 0 。
图13-4 中给出了总方差的百分比,可以看出来在开始的几个主成分之后,方差就会迅速下降。
表 13-1 给出了这些主成分所对应的方差百分比和累积方差百分比。浏 览 “ 累积方差百分比( % )” 这一列就会注意到 , 前六个主成分就覆盖了数据 96.8% 的方 差 , 而前 20 个主成分覆盖了 99.3%的方差。这就表明了,如果保留前 6 个而去除后 584 个 主 成 分 ,我们就可以实现大概 100 : 1 的压缩比。另 外 ,由于舍弃了噪声的主成分,将后面的主成分去除便使得数据更加干净。
于 是 ,我们可以知道在数据集的前面多个主成分中所包含的信息量。我们可以尝试不同的截断值来检验它们的性能。有些人使用能包含90%信息量的主成分数量, 而其他人使用前20个主成分。 我们无法精确知道所需要的主成分数目, 必须通过在实验中取不同的值来确定。有效的主成分数目则取决于数据集和具体应用。
上述分析能够得到所用到的主成分数目, 然后我们可以将该数目输人到PCA算法中, 最后得到约简后数据就可以在分类器中使用了。
13.4 总结
降维技术使得数据变得更易使用,并且能够去除数据中的噪声,使得其他机器学习任务更加精确。