书上运行时发生错误:
Exception has occurred: TypeError
unsupported operand type(s) for /: ‘map’ and ‘int’
datArr = [map(float,line) for line in stringArr]
修改为
datArr = [list(map(float,line)) for line in stringArr] #map对象转化为List对象
什么是降维?
对于电视上的一场足球比赛,在显示器上是百万像素;如果我们想要找到球的位置,人们实时地将显示器上的百万像素转换成了一个三维图像,也就是球的位置。这个过程,人们已经将数据从一百万维降至三维。
数据是接受的原始材料,其中可能包含噪声和不相关信息。信息是指数据中的相关部分。
13.1 降维技术
-
对数据进行简化的原因:
1)使数据集更易使用 2)降低很多算法的计算开销 3)去除噪声 4)使得结果易懂
-
第一种降维的方法是主成分分析(Principal Component Analysis,PCA).在PCA中,数据从原来的坐标系转换到了新坐标系。新坐标系的选择是由数据本身决定的。第一个新坐标轴选择的是原始数据中方差最大的方向,第二个新坐标轴的选择和第一个坐标轴正交且具有最大方差的方向。该过程一直重复,重复次数为原始数据中特征的数目。我们会发现,大部分方差都包含在最前面的几个新坐标轴中。因此,我们可以忽略余下的坐标轴,即对数据进行了降维处理。(对于数据的方差,可以这么理解:方差使数据区分开来,如果方差为0,说明某些特征是相似的,故可以舍去。)
-
另一种降维技术是因子分析(Factor Analysis).在因子分析中,我们假设在观察数据的生成中有一些观察不到的隐变量(latent variable).假设观察数据是这些隐变量和某些噪声的线性组合。那么隐变量的数据可能比观察数据的数目少,也就是说通过找到隐变量就可以实现数据的降维。
-
还有一种是独立成分分析(Independent Component Analysis,ICA).ICA假设数据是从N个数据源生成的,假设数据为多个数据源的混合观察结果,这些数据源之间在统计上是相互独立的,而在PCA中只假设数据是不相关的。同因子分析一样,如果数据源的数目少于观察数据的数目,则可以实现降维过程。
13.2 PCA
优点:降低数据的复杂性,识别最重要的多个特征
缺点:不一定需要,且可能损失有用信息
13.2.1 移动坐标轴
- 在PCA中,我们对数据的坐标进行了旋转,该旋转过程取决于数据的本身。第一条坐标轴旋转到覆盖数据的最大方差位置,即图中的直线B。数据的最大方差给出了数据的最重要信息。
- 在选择了覆盖数据最大差异性的坐标轴之后,我们选择了第二条坐标轴。假如该坐标轴与第一条坐标轴正交(orthognal),它就是覆盖数据次大差异性的坐标轴。在上图中,直线C就是第二条坐标轴。利用PCA,我们降数据坐标轴旋转至数据角度上的那些最重要的方向。
- 为什么要选择正交?
回忆一下线代里的正交基,一个平面内的数据能由互相正交的两个向量表示。
PCA选择正交的坐标轴,能最大程度上表示所有的数据,因为所有的数据都可以由它们线性组合得到。数据是接受的原始材料,其中可能包含噪声和不相关信息。信息是指数据中的相关部分。特征值为0的特征是其他特征的副本,也就是说,它们可以通过其他特征来表示,而本身并没有提供额外的信息。 - 通过数据集的协方差矩阵及其特征值分析,我们就可以求得主成分的值。一旦得到了协方差矩阵的特征向量,我们就可以保留最大的N个值。这些特征向量也给出了N个最重要特征的真实结构。我们可以通过将数据乘上这N个特征向量而将它转换到新的空间。(这使我想到了CNN算法里的卷积过程)
- 特征值分析是线性代数中的领域,它能够通过数据的一般格式来揭示数据的“真实”结构,即我们常说的 特征向量和特征值。
13.2.2 在Numpy中实现PCA
将数据转换成前N个主成分的伪代码如下
去除平均值
计算协方差矩阵
计算协方差矩阵的特征值和特征向量
将特征值从大到小排序 #特征值越大,代表方差越大;不同的特征值对应的特征向量相互正交
保留前N个特征向量
将数据转换到上述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()]
datArr = [list(map(float,line)) for line in stringArr] #map对象转化为List对象
return mat(datArr)
def PCA(dataMat,topNfeat=9999999):
#去平均值
meanVals = mean(dataMat,axis=0)
meanRemoved = dataMat -meanVals
#协方差矩阵的特征值及特征向量
covMat = cov(meanRemoved,rowvar=0)
eigVals,eigVects = linalg.eig(mat(covMat))
eigValInd =argsort(eigVals) #从小到大排序,返回排序前的索引
eigValInd = eigValInd[:-(topNfeat+1):-1]
redEifVects = eigVects[:,eigValInd]
#将数据转换到新空间
lowDataMat = meanRemoved * redEifVects
reconMat = (lowDataMat * redEifVects.T) + meanVals #重构数据,如果没有剔除数据,则reconMat和原始数据重合
return lowDataMat,reconMat
def Plot(dataMat,reconMat):
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()
if __name__ == '__main__':
dataMat = loadDataSet('./M_13_PCA/testSet.txt')
print(dataMat.shape)
lowDataMat,reconMat = PCA(dataMat,1)
print(lowDataMat.shape)
Plot(dataMat,reconMat)
13.3 示例:利用PCA对半导体制造数据降维
#将NaN数据替换成平均值
def replaceNanWithMean():
dataMat = loadDataSet('./M_13_PCA/secom.data',' ')
numFeat = shape(dataMat)[1] #特征数量
for i in range(numFeat):
#计算所有非NaN的平均值
meanVal = mean(dataMat[nonzero(~isnan(dataMat[:,i].A))[0],i])
#将所有NaN置为平均值
dataMat[nonzero(isnan(dataMat[:,i]))[0],i] = meanVal
return dataMat
我们可以知道在数据集的前面多个主成分中所包含的信息量。我们可以尝试不同的截断值来检验它们的性能。
13.3 本章小结
降维技术使得数据变得更易使用,并且它们往往能够去除数据中的噪声。降维往往作为预处理步骤,在数据应用到其他算法之前清洗数据。
本章中的PCA将所有数据集都调入了内存,如果无法做到,就需要其他的方法来寻找其特征值。