欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

数据简化之PCA

程序员文章站 2022-07-16 18:08:35
...

降维,降低维度(dimensionality reduction),将高维数据经过技术处理降低到低纬度下,数据更容易进行处理,其相关特性更容易在数据中明显的显示出来。

 

对数据简化的好处:

1 使得数据集更容易使用

2 降低很多算法的开销

3 去除噪声

4 使得结果易懂

 

本文了解的降维技术叫主成分分析(Principal Component AnalysisPCA

PCA中,数据从原来的坐标系转换到了新的坐标系,新坐标系的选择是由数据本身决定的。第一个新坐标轴选择的是原始数据中方差大的方向,第二个新坐标轴的选择和第一个坐标轴正交且具有大方差的方向。该过程一直重复,重复次数为原始数据中特征的数目。我们会发现,大部分方差都包含在前面的几个新坐标轴中。因此,我们可以忽略余下的坐标轴,即对数据进行了降维处理

效果图如下:

数据简化之PCA

蓝点为原样本数据,红点为降维后的数据,可以看得出从面降为了线,从2维降低为1维。

 

矩阵协方差的意义代表特性之间的关联性,可用来进行特性分析。

一旦获得协方差矩阵,就可以通过linalg.eig()获得特性向量和特性值。

在等式Av = λv中,v 是特征向量,λ是特征值。特征值都是简单的标量值,因此Av = λv代表的是:如果特征向量v被某个矩阵A左乘,那么它就等于某个标量λ乘以v

 

PCApython代码如下:

#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个特性,所有特征值eigVals590个值,结果如下:

数据简化之PCA

数据简化之PCA

数据简化之PCA


可以看到特征值从千万级开始骤降到十万级,然后慢慢衰减到个位级,最终变为0。它们可以通过其他特征来表示,而本身并没有提供额外的信息。

 

再对前20个最大的特征值进行分析:

数据简化之PCA

6个特征值的和占据总特征值和的96.8%,所以我们只要保留前6个特征向量和特征值,对数据进行PCA处理,就可以将原始数据进行1001的压缩,方便我们后续的算法处理。

 

最后澄清一个误区,压缩并不是代表着为了减少消耗提高性能带来最终学习精度的丢失,因为在压缩工程中会过滤掉噪声等有负面效果的影响因素,反正能使学习任务更加精准。