机器学习实战第十三章 利用PCA来简化数据

利用PCA来简化数据

什么是PCA

PCA的全称是Principal Component Analysis,也即主成分分析,说人话就是改变坐标系来让数据更好处理(降维)。

为什么说改变坐标系就能够让数据更好处理呢?
诸位既然参加过高考,学过高数,那么多半是学过直角坐标系与极坐标系,有的时候换个坐标就能让结果好很多。只不过极坐标是为了简化计算过程,而PCA是为了对数据降维。

那么什么是降维呢?书上的例子就非常的直观:假设我们要对下图进行分类,那么得到的决策边界多半是这样子:
在这里插入图片描述
那么我们是用了几个变量(也可以视作维度)来学习和描述决策边界的呢?二维对不对。因为所有的点都是二维的,然后两个决策平面可以描述为这种形式:
y = a x + b y = ax+b y=ax+b
但是,假如我们转换一下坐标,将原图的坐标沿着绿色的线,转化为这种形式:
在这里插入图片描述
值得注意的是,左图旋转后应该还是会有高度的呀,不可能变为右图中的一条直线。但是,我们要做分类问题的话,旋转坐标后高度还重要吗?显然不会,高度信息在旋转后不过是一些无意义的噪声罢了。因此去掉高度信息后就得到了右图的形式。而这便是PCA,用比较标准的定义来讲的话,就是:

  • 主成分分析(Principal Component Analysis,PCA)是一种常用的降维技术,用于将高维数据集转换为低维表示。它的目标是通过线性变换,将原始数据投影到一个新的坐标系中,使得在新的坐标系下数据的方差最大化。
  • 其基本思想是找到一组正交的基向量,称为主成分,它们按照方差的降序排列。第一个主成分是原始数据中方差最大的方向,第二个主成分是在第一个主成分方向上的方差最大的方向,以此类推。这些主成分捕捉了数据中的主要模式和结构。

代码实现

知道了其基本思想,我们就可以开始用代码实现了:

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]
    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)
    # 从小到大排序,最大的N个特征值的下标
    eigValInd = eigValInd[:-(topNfeat+1):-1]
    redEigVects = eigVects[:,eigValInd]
    
    # 将数据转换到新空间
    lowDDataMat = meanRemoved * redEigVects
    reconMat = (lowDDataMat * redEigVects.T) + meanVals
    return lowDDataMat, reconMat
    
if __name__ == '__main__':
    dataMat = loadDataSet('testSet.txt')
    lowDMat, reconMat = pca(dataMat, 1)
    print(shape(lowDMat))
    
    import matplotlib
    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], marker='^', s=90)
    ax.scatter(reconMat[:,0].flatten().A[0], reconMat[:,1].flatten().A[0], marker='o', s=50, c='red')
    plt.show()

第一个函数是读取数据,除了要注意一下py2与py3的语法差异就没什么特别的了,重点在第二个函数,去除均值的目的是为了消除数据的整体平移对主成分分析(PCA)结果的影响,从而更好地捕捉数据的方差结构。然后我们要计算出协方差矩阵和特征矩阵。最后拿这个协方差矩阵去确定如何转换坐标系。
注:

  • 协方差矩阵是描述数据特征之间相关性的矩阵。它的每个元素表示了对应特征之间的协方差,反映了它们的相关性程度。在PCA中,通过计算数据矩阵的协方差矩阵,可以获取数据的方差和相关性信息。
  • 特征值是协方差矩阵的特征值,代表了协方差矩阵的特征向量对应的重要程度。在PCA中,通过计算协方差矩阵的特征值和特征向量,可以确定数据中方差最大的方向,即主成分。特征值表示了主成分的方差大小,越大的特征值意味着对应的主成分解释了更多的数据方差。
  • 利用协方差矩阵和特征值,可以进行主成分的选择和降维。一般来说,我们会按照特征值的大小降序排列,选取前N个最大的特征值对应的特征向量作为主成分,这些主成分包含了数据中最重要的方差结构。根据选取的主成分,可以将原始数据映射到新的低维空间,实现数据的降维操作。

运行结果如下:
在这里插入图片描述

实验

现在我们做一个小实验,用来验证算法的效果。由于数据维度太多,没有办法可视化了,只能输出特征矩阵看一下:

from numpy import *

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]
    return mat(datArr)


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


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)
        

输出如下:

[ 5.34151979e+07  2.17466719e+07  8.24837662e+06  2.07388086e+06
  1.31540439e+06  4.67693557e+05  2.90863555e+05  2.83668601e+05
  2.37155830e+05  2.08513836e+05  1.96098849e+05  1.86856549e+05
  1.52422354e+05  1.13215032e+05  1.08493848e+05  1.02849533e+05
			·						·					·
			·						·					·
			·						·					·
  0.00000000e+00  0.00000000e+00  0.00000000e+00  0.00000000e+00
  0.00000000e+00  0.00000000e+00  0.00000000e+00  0.00000000e+00
  0.00000000e+00  0.00000000e+00  0.00000000e+00  0.00000000e+00
  0.00000000e+00  0.00000000e+00  0.00000000e+00  0.00000000e+00
  0.00000000e+00  0.00000000e+00]

可以看到有很多特征值为0,这意味着可以降低非常多的维度。也就是说算法的效果非常好。

小结

由于还没有碰到过真正难以处理的数据,因此本章所提到的算法我还没有办法亲身体会其能力,但是就实验结果来看,它对于数据的处理能力的确是非常强。我感觉它跟注意力机制有一点点像,都是为了把更多的注意力分贝给更重要的内容,如果以后注意力机制发展到头了,内容过多,是否可以参考这个算法的思想,舍弃掉一些不重要的内容呢。感觉这可能会是一个很有意思的思路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值