• 机器学习实战 10-PCA


    1 先备知识

    1.1 一些统计学认识

    方差: 用来描述样本偏离中心程度的量

    协方差:用来描述两变量 X,Y 相互关系的量,协方差越大,对彼此影响越大,协方差等于0,两者独立

    协方差矩阵:         

    如果一组样本 y1,.......ym ,每个样本是 n 维行向量,则这组样本的协方差矩阵为:

    注意:矩阵中的 x1,......xn ,指的是上面m个样本的每一维值,则 xn 为 m 维列向量。

    理解:由 m 个样本确定的 n 维空间,协方差矩阵的每一列表示的是所有维对某一维分别影响值(即相关性),描述这个 n 维空间。 协方差矩阵的对角线上为各个特征的方差。 

    1.2 一些矩阵论知识

    特征值和特征向量:

    已经学习过很久的基础知识,说它们是矩阵中最重要的一环也不为过,但当我们学习各种骚操作计算这两值的时候,有没有想过它们是何意义,或者说有什么作用?再看公式,如下 :

    解释:A 将 α 做了一个变换,向量α在变换过后,方向没变,长度被拉伸 λ 倍。如图所示:

    如果A是一个二维,则找到两个特征向量分别表示两个最具有代表性的方向,特征向量在此方向上经过A变换,方向不会改变,只会拉伸λ倍。这两个方向上包含矩阵A信息最多。

    具体可参观:http://k.sina.com.cn/article_6367168142_17b83468e001005yrv.html

    协方差矩阵对角化:

    对称矩阵的一些性质:

      1. 实对称矩阵不同的特征值对应的特征向量必然正交

      2. 设 λ 是 k 重特征值,则 λ 对应必有 k 个线性无关的特征向量,并可将其对角化

    由上可知一个 n*n 的对角矩阵一定可以找到 n 个线性无关的正交特征向量,正交阵 P 由这 n 个特征向量组成,则:

    基变换:

    如图,在同一空间里,在不同基下坐标表达不同,图中向量在基变换以后,有一个方向的坐标已经变成0。其中,矩阵A则用来表示这个线性变换过程,称过渡矩阵。

    2 PCA原理

    2.1 特征降维

    我们经常遇到一大批数据,千万级或者亿级别的数据,这些数据有很多个特征,但是这些特征很有可能有许多特征起到的作用是重复的(比如一种物体密度是一样的,那么这个物体的体积和重量这两个特征有重复),如果去除这些重复的,那么数据会苗条许多。另外有一部分维度的特征可能对于你本身想要研究的方向是噪声,去除他们,数据会更干净。所以,特征降维是一门重要技术,而PCA(主成分分析)就是一种特征降维方法。总结其作用如下:

      1. 去除噪声

      2. 降低算法计算复杂度,就是快一点

      3. 相对的要简洁易懂一点

    2.2 PCA

    如图中是一组二维数据,但是其分布主要沿着图中星星这条直线上,所以我们可以将其投影到这条直线上进行研究,这样就从二维降到了一维。

    理论分析(参考周志华《机器学习》):

    在正交属性空间中的样本点,用一个超平面(直线高阶推广)对所有样本恰当表达,这个超平面满足下面两个性质:

      • 最近重构性:样本到这个超平面的距离都足够近(损失最小)
      • 最大可分性:样本在这个超平面上的投影都尽可能分开(就是方差最大)

    用这两个性质逆向推导,能够得到同样的条件:

    其中 X 为 m 个 n 维特征的样本(已经中心化 ),W 为新的坐标系(n 维),取其中前 N (即对应于λ前 N 大的)维,经过变换,样本变为 N 维,从而达到降维目的。

    算法过程:

    注意:周老师书中的样本是横向排列,以下自我分析时,样本取的是纵向排列(日常分析数据时习惯使然)。

    2.3 个人愚见

    我们希望找到一个新的基向量组,原始数据在这些新基向量组下表示时,在每个属性上散布广,即方差大,且任何两个属性间的相关性为0。取出数据散布最广的前 N 个维度,将原始数据以新的基向量为参考坐标系表示出来,数据就能得到压缩。

    上面 X^T·X 为样本的协方差矩阵,表示的各特征维度之间的相关关系,如果我们能使这个协方差矩阵对角化,那么除对角线之外的其他元素均为0,各维度之间无关,即属性间的相关性为0。问题就变成了我们如何使协方差矩阵对角化。以上已经给出对角化的方法,即求协方差的特征值和特征向量即可。

    其中 P 为特征向量组成的正交阵,即为新基。 X 为 m 个 n 维特征的样本,原始基可以理解为 n 阶单位阵,默认坐标的表示方式为列向量。

    这样我们在新基下的样本 Z 的协方差矩阵变为对角阵,各属性间毫无瓜葛,选取方差较大(即λ较大)的 N 维,便可得到降维后的数据,此数据保留大部分原数据信息。从这也能看出,在特征值大的特征向量方向保存信息多。

    3 Python 实现

    3.1 小试牛刀

     1 from numpy import *
     2 import matplotlib.pyplot as plt
     3 
     4 # 读取文件数据,并返回浮点数矩阵形式
     5 def loadDataSet(fileName,delim='	'):
     6     fr=open(fileName)
     7     stringArr=[line.strip().split(delim) for line in fr.readlines()]
     8     datArr=[list(map(float,line)) for line in stringArr]
     9     return mat(datArr)
    10 
    11 # PCA
    12 def pca(dataMat,topNfeat=9999999):
    13     meanVals=mean(dataMat,axis=0)              # 按每列求取平均值
    14     meanRemoved=dataMat-meanVals               # 中心化,即去除平均值
    15     covMat=cov(meanRemoved,rowvar=0)           # 计算协方差矩阵
    16     # covMat=meanRemoved.T*meanRemoved
    17     eigVals,eigVects=linalg.eig(mat(covMat))   # 计算协方差矩阵的特征值和特征向量
    18     eigValInd=argsort(eigVals)                 # 将特征值从小到大排列
    19     eigValInd=eigValInd[:-(topNfeat+1):-1]     # 取前 N 大的特征值索引
    20     redEigVects=eigVects[:,eigValInd]          # 保留最上面 N 个特征向量
    21     lowDDataMat=meanRemoved*redEigVects        # 将数据转换为由 N 个特征向量构成的空间中
    22     reconMat=(lowDDataMat*redEigVects.T)+meanVals
    23     return lowDDataMat,reconMat
    24 
    25 dataMat=loadDataSet('testSet.txt')
    26 print(dataMat.shape)
    27 lowDMat,reconMat=pca(dataMat,1)
    28 print(lowDMat.shape)
    29 fig=plt.figure()
    30 ax=fig.add_subplot(111)
    31 ax.scatter(dataMat[:,0].flatten().A[0],dataMat[:,1].flatten().A[0])
    32 ax.scatter(reconMat[:,0].flatten().A[0],reconMat[:,1].flatten().A[0],marker='*',c='c')
    33 plt.show()

    得到上面那张图,将数据都投影到星星线上了:

    3.2 利用 PCA 对半导体制造数据降维

     1 from numpy import *
     2 import matplotlib.pyplot as plt
     3 
     4 # 读取文件数据,并返回浮点数矩阵形式
     5 def loadDataSet(fileName,delim='	'):
     6     fr=open(fileName)
     7     stringArr=[line.strip().split(delim) for line in fr.readlines()]
     8     datArr=[list(map(float,line)) for line in stringArr]
     9     return mat(datArr)
    10 
    11 # PCA
    12 def pca(dataMat,topNfeat=9999999):
    13     meanVals=mean(dataMat,axis=0)              # 按每列求取平均值
    14     meanRemoved=dataMat-meanVals               # 中心化,即去除平均值
    15     covMat=cov(meanRemoved,rowvar=0)           # 计算协方差矩阵
    16     # covMat=meanRemoved.T*meanRemoved
    17     eigVals,eigVects=linalg.eig(mat(covMat))   # 计算协方差矩阵的特征值和特征向量
    18     eigValInd=argsort(eigVals)                 # 将特征值从小到大排列
    19     eigValInd=eigValInd[:-(topNfeat+1):-1]     # 取前 N 大的特征值索引
    20     redEigVects=eigVects[:,eigValInd]          # 保留最上面 N 个特征向量
    21     lowDDataMat=meanRemoved*redEigVects        # 将数据转换为由 N 个特征向量构成的空间中
    22     reconMat=(lowDDataMat*redEigVects.T)+meanVals
    23     return lowDDataMat,reconMat
    24 
    25 # 将数据中的 NaN 替换成平均值
    26 def replaceNanWithMean():
    27     datMat=loadDataSet('secom.data',' ')
    28     numFeat=shape(datMat)[1]
    29     # 遍历每一个特征值
    30     for i in range(numFeat):
    31         # 计算非 NaN 的平均值
    32         meanVal=mean(datMat[nonzero(~isnan(datMat[:,i].A))[0],i])
    33         # 填充平均值
    34         datMat[nonzero(isnan(datMat[:,i].A))[0],i]=meanVal
    35     return datMat
    36 
    37 dataMat=replaceNanWithMean()
    38 meanVals = mean(dataMat, axis=0)  # 按每列求取平均值
    39 meanRemoved = dataMat - meanVals  # 中心化,即去除平均值
    40 covMat = cov(meanRemoved, rowvar=0)  # 计算协方差矩阵
    41 eigVals, eigVects = linalg.eig(mat(covMat))  # 计算协方差矩阵的特征值和特征向量
    42 print(eigVals)
    43 
    44 fig=plt.figure()
    45 ax=fig.add_subplot(121)
    46 ax.plot(eigVals[:20],marker='*',c='g')
    47 bx=fig.add_subplot(122)
    48 bx.pie(eigVals,autopct='%1.1f',radius=1.3)
    49 plt.show()
    View Code

    最后得到下面关于方差百分比的图:

     

    结论:可以发现半导体590个特征中,前6个主成分覆盖了数据的96.8%的方差,如果去除后面584个特征,将能实现很好的压缩,数据简洁,噪声也被去除,更易处理

    参考文献:

    1. 周志华 《机器学习》,peter 《机器学习实战》
    2. PCA的数学原理(非常值得阅读)!!! https://blog.csdn.net/xiaojidan2011/article/details/11595869

    3. 看完这篇图解 PCA,面试再也不担心  https://zhuanlan.zhihu.com/p/44371812

  • 相关阅读:
    Effective STL 学习笔记 Item 16:vector, string & C API
    在 Python 中使用 GDB 来调试 转载
    Effective STL 学习笔记14: Use reserve to avoid unnecessary reallocations.
    Effective STL 学习笔记: 多用 vector & string
    Effective STL 学习笔记: Thread Safety and STL Container
    Effective STL 笔记 -- Item 6 ~ 7: Container and Object Pointer
    How to omit h1 title heading in HTML export
    Introduction to MWB Minor Mode
    Effective STL 笔记 -- Item 9: Choose carefully among erasing options
    Redis简介
  • 原文地址:https://www.cnblogs.com/Ray-0808/p/10975985.html
Copyright © 2020-2023  润新知