数据简化之PCA
降维,降低维度(dimensionality reduction),将高维数据经过技术处理降低到低纬度下,数据更容易进行处理,其相关特性更容易在数据中明显的显示出来。
对数据简化的好处:
1 使得数据集更容易使用
2 降低很多算法的开销
3 去除噪声
4 使得结果易懂
本文了解的降维技术叫主成分分析(Principal Component Analysis,PCA)
在PCA中,数据从原来的坐标系转换到了新的坐标系,新坐标系的选择是由数据本身决定的。第一个新坐标轴选择的是原始数据中方差大的方向,第二个新坐标轴的选择和第一个坐标轴正交且具有大方差的方向。该过程一直重复,重复次数为原始数据中特征的数目。我们会发现,大部分方差都包含在前面的几个新坐标轴中。因此,我们可以忽略余下的坐标轴,即对数据进行了降维处理
效果图如下:
蓝点为原样本数据,红点为降维后的数据,可以看得出从面降为了线,从2维降低为1维。
矩阵协方差的意义代表特性之间的关联性,可用来进行特性分析。
一旦获得协方差矩阵,就可以通过linalg.eig()获得特性向量和特性值。
在等式Av = λv中,v 是特征向量,λ是特征值。特征值都是简单的标量值,因此Av = λv代表的是:如果特征向量v被某个矩阵A左乘,那么它就等于某个标量λ乘以v
求PCA的python代码如下:
#dataMat 原始数据样本
#topNfeat 降维后要保留的特性数
def pca(dataMat, topNfeat=9999999) :
#前两行,去平均值
meanVals = mean(dataMat, axis=0)
meanRemoved = dataMat - meanVals
#求协方差矩阵
#若rowvar=0,说明传入的数据一行代表一个样本,若非0,说明传入的数据一列代表一个样本
covMat = cov(meanRemoved,rowvar=0)
#利用linalg.eig求解covMat的特性项量和特性值
#eigVal是特征值
#eigVects是特征向量,二者一一对应
eigVals, eigVects = linalg.eig(mat(covMat))
#对特性值索引进行正向排序
eigValInd = argsort(eigVals)
#取最后的也就是最大的特性值索引
#list[a:b:c]代表从下标a开始到b,步长为c
eigValInd = eigValInd[:-(topNfeat+1):-1]
#得到最大的n个特性向量
redEigVects = eigVects[:,eigValInd]
#利用特性向量将原始数据转化到新的空间的数据集(降维)
#lowDDataMat就是降维后的数据
lowDDataMat = meanRemoved * redEigVects
#reconMat为降维后重构回来的数据,用于与未降维前dataMat数据进行对比分析
reconMat = (lowDDataMat * redEigVects.T) + meanVals
return lowDDataMat, reconMat
辅助函数,加载数据样本的代码:
#加载文档并以delim分割每行
def loadDataSet(fileName, delim='\t') :
fr = open(fileName)
stringArr = [line.strip().split(delim) for line in fr.readlines()]
dataArr = [list(map(float, line)) for line in stringArr]
return mat(dataArr)
图片中样本集在git上(https://github.com/yejingtao/forblog/blob/master/MachineLearning/trainingSet/pca/testSet.txt)
对蓝色数据降维处理后再图形化展示的代码如下:
dataMat = loadDataSet('C:\\2017\\提高\\机器学习\\训练样本\\pca\\testSet.txt')
lowDDataMat, reconMat = pca(dataMat, 1)
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(dataMat[:, 0].flatten().A[0], dataMat[:, 1].flatten().A[0])
ax.scatter(reconMat[:, 0].flatten().A[0], reconMat[:, 1].flatten().A[0], c='red')
plt.show()
上面案例只是2维降低为1维,真正使用中可以通过降维将特性降低到更理想的情况,看下面这个例子。
数据集在git上(https://github.com/yejingtao/forblog/blob/master/MachineLearning/trainingSet/pca/secom.data) 数据有590个特性。我要对其进行主成分分析之前发现有很多特性值为空,用’Nan’表示,在博文《Logistic回归(2)》中有介绍过如何对数据空值进行预处理,当时基于Logicstic回归的特性给出的处理意见是用0去补齐,但是在这里不合适,因为像温度、经纬度等0就有了真实的意义,这里使用均值法来补齐空特性,需要给代码添加一个辅助函数:
#对空特性值做平均值处理
def replaceNanWithMean(fileName,delim='\t') :
dataMat = loadDataSet(fileName,delim)
numFeat = shape(dataMat)[1]
#对每个特性做处理
for i in range(numFeat) :
#计算出所有非空值的平均值
meanVal = mean(dataMat[nonzero(~isnan(dataMat[:,i].A))[0],i])
#用平均值来替换空值
dataMat[nonzero(isnan(dataMat[:,i].A))[0],i] = meanVal
return dataMat
在进行PCA之前,我们还需要理性的判断入参topNfeat传值大小,也就是说到底需要将590维降低为几维?我们先来观察下特性值分析:
dataMat = replaceNanWithMean('C:\\2017\\提高\\机器学习\\训练样本\\pca\\secom.data',delim=' ')
meanVal = mean(dataMat,axis=0)
meanRemoved = dataMat-meanVal
covMat = cov(meanRemoved,rowvar=0)
eigVals, eigVects = linalg.eig(mat(covMat))
因为有590个特性,所有特征值eigVals有590个值,结果如下:
可以看到特征值从千万级开始骤降到十万级,然后慢慢衰减到个位级,最终变为0。它们可以通过其他特征来表示,而本身并没有提供额外的信息。
再对前20个最大的特征值进行分析:
前6个特征值的和占据总特征值和的96.8%,所以我们只要保留前6个特征向量和特征值,对数据进行PCA处理,就可以将原始数据进行100:1的压缩,方便我们后续的算法处理。
最后澄清一个误区,压缩并不是代表着为了减少消耗提高性能带来最终学习精度的丢失,因为在压缩工程中会过滤掉噪声等有负面效果的影响因素,反正能使学习任务更加精准。
下一篇: IPFS web ui 运行报错