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

机器学习实战(十一)利用PCA来简化数据

程序员文章站 2022-07-16 18:12:45
...

第十三章 利用PCA来简化数据

13.1 降维技术

数据降维的原因:

1)可以使数据显示更加容易
2)使得数据集更容易使用
3)降低算法计算开销
4)去除噪声
5)使得结果易懂

降维主要有三种方法,依次介绍如下。

13.1.1 主成分分析(PrincipalComponentAnalysis,PCA)

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

13.1.2 因子分析(Factor Analysis)

在因子分析中,我们假设在观察数据的生成 中 有一 些观察 不 到的隐 变量 ( latentvariable )。假设观察数据是这些隐变量和某些噪声的线性组合 。那么隐变量的数据可能比观察数据的数目少,也就是说通过找到隐变量就可以实现数据的降维。

13.1.3 独立成分分析(Independent Component Analysis, ICA)

ICA假设数据是从 N 个数据源生成的,这一点和因子分析有些类似。 假设数据为多个数据源的混合观察结果,这些数据源之间在统计上是相互独立的,而在 ? 0 人中只假设数据是不相关的。同因子分析一样,如果数据源的数目少于观察数据的数目,则可以实现降维过程。

PCA应用最为广泛,下面来介绍PCA。

13.2 PCA

13.2.1 移动坐标轴和降维

第一步:坐标轴旋转

机器学习实战(十一)利用PCA来简化数据

图13-1中的大量数据点,则B是覆盖最多的线条。PCA中,我们对数据的坐标进行了旋转,该旋转过程取决于数据本身。

第一条坐标轴:旋转到覆盖数据的最大方差位置(也就是覆盖数据最大差异性的坐标轴),即图中的直线B,数据的最大方差给出了数据的最重要的信息。

第二条坐标轴:选择与第一条坐标轴垂直的坐标轴,也就是正交坐标轴(覆盖数据次打差异性的坐标轴)。

利用PCA,我们将数据坐标轴旋转至数据角度上的那些重要的方向。

机器学习实战(十一)利用PCA来简化数据

坐标轴旋转并未减少数据的维度

第二步:降维

如上图,其中包含着 3 个不同的类别。要区分这 3 个 类 别 ,可以使用决策树。我们还记得决策树每次都是基于一个特征来做决策的。我 们会发现,在 x轴上可以找到一些值,这些值能够很好地将这 3 个类别分开。这 样 ,我们就可能得到一些规则,比 如 当 0 < 4 ) 时 ,数据属于类别 0 。如果使用 SVM这样稍微复杂一点的分类器,我们就会得到更好的分类面和分类规则,比如当(w0 * x + w1 * y + b) > 0 时 ,数据也属于类别 0 。 SVM可能比决策树得到更好的分类间隔,但是分类超平面却很难解释。
机器学习实战(十一)利用PCA来简化数据

通过PCA进行降维处理,我们就可以同时获得 SVM和决策树的优点:

1)一 方 面 ,得到了和决策树一样简单的分类器,同时分类间隔和 SVM一样好,如上图,其中的数据来自于上面的图并经 过PCA转换之后绘制而成的,如果仅使用原始数据,那么这里的间隔会比决策树的间隔更大。

2) 另 外 ,由于只需要考虑一维信息,因此数据就可以通过比 S V M 简单得多的很容易采用的规则进行区分 。

在上图中,我们只需要一维信息即可,因为另一维信息只是对分类缺乏贡献的噪声数据,在二位平面下,这一点看上去微不足道,但是如果在高维空间下则意义重大。

PCA实现:

第一个主成分:数据差异性最大(即方差最大)的方向

第二个主成分:数据差异性的次大(与第一个主成分方向正交)的方向

如何求取主成分的值:

数据集的协方差阵及其特征值分析

如何转化到特征空间:

得到协方差矩阵的特征向量,就可以保留最大的N个值,这些特征向量也给出了B个最重要特征的真实结构,我们可以通过将数据乘上这N个特征向量而将其转换到新的空间。

13.2.2 统计学基本概念

1)均值:X¯=i=1nXin

2)标准差:s=i=1n(XiX¯)2n1

3)方差:s2=i=1n(XiX¯)2n1

4)协方差:

标准差和方差一般是用来描述一维数据的,但现实生活中常常遇到含有多维数据的数据集,协方差就是用来度量两个随机变量关系的统计量。

可以通俗的理解为:两个变量在变化过程中是同方向变化?还是反方向变化?同向或反向程度如何?
你变大,同时我也变大,说明两个变量是同向变化的,这时协方差就是正的。
你变大,同时我变小,说明两个变量是反向变化的,这时协方差就是负的。
从数值来看,协方差的数值越大,两个变量同向程度也就越大。反之亦然。

公式:
Cov(X,Y)=i=1n(XiX¯)(YiY¯)n1=E[(Xμx)(Yμy)]

性质:

Cov(X,X)=var(X)
Cov(X,Y)=Cov(Y,X)

意义:如果有X,Y两个变量,每个时刻的“X值与其均值之差”乘以“Y值与其均值之差”得到一个乘积,再对这每时刻的乘积求和并求出均值(其实是求“期望”,但就不引申太多新概念了,简单认为就是求均值了)。

13.2.3 在Numpy中实现PCA

将数据转换为前N个主成分的伪代码如下:

机器学习实战(十一)利用PCA来简化数据

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()]
    dataArr = [map(float,line) for line in stringArr]
    print(mean(mat(dataArr)))
    return mat(dataArr)


def pca(dataMat,topN=999999):
    # 形成样本矩阵,样本中心化

    meanVals= mean(dataMat,axis=0)
    meanRemoved = dataMat - meanVals
    # 计算样本矩阵的协方差矩阵
    covMat = cov(meanRemoved,rowvar=0)
    #  对协方差矩阵进行特征值分解,选取最大的 p 个特征值对应的特征向量组成投影矩阵
    eigVals,eigVects =  linalg.eig(mat(covMat))
    eigValInd = argsort(eigVals)
    eigValInd = eigValInd[:-(topN+1):-1]
    redEigVects = eigVects[:,eigValInd]
    # 对原始样本矩阵进行投影,得到降维后的新样本矩阵
    lowDDataMat = meanRemoved * redEigVects
    reconMat = (lowDDataMat * redEigVects.T)+meanVals
    return lowDDataMat,reconMat


if __name__=='__main__':
    dataMat = mat(loadtxt('testSet.txt'))
    lowMat,reconMat = pca(dataMat,1)
    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()

书中代码运行有误

相比书中的修改:dataMat = mat(loadtxt('testSet.txt'))

结果:

机器学习实战(十一)利用PCA来简化数据
上图显示了原始数据集和第一主成分

13.3 实例:利用PCA降维技术对半导*造数据降维

缺失值处理:取平均值代替缺失值,平均值根据非NaN得到。


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()]
    dataArr = [map(float,line) for line in stringArr]
    return mat(dataArr)

def pca(dataMat,topN=999999):
    # 形成样本矩阵,样本中心化
    meanVals= mean(dataMat,axis=0)
    meanRemoved = dataMat - meanVals
    # 计算样本矩阵的协方差矩阵
    covMat = cov(meanRemoved,rowvar=0)
    #  对协方差矩阵进行特征值分解,选取最大的 p 个特征值对应的特征向量组成投影矩阵
    eigVals,eigVects =  linalg.eig(mat(covMat))
    eigValInd = argsort(eigVals)
    eigValInd = eigValInd[:-(topN+1):-1]
    redEigVects = eigVects[:,eigValInd]
    # 对原始样本矩阵进行投影,得到降维后的新样本矩阵
    lowDDataMat = meanRemoved * redEigVects
    reconMat = (lowDDataMat * redEigVects.T)+meanVals
    return lowDDataMat,reconMat

def replaceNanWithMean():
    datMat = loadDataSet('secom.data', ' ')
    numFeat = shape(datMat)[1]
    for i in range(numFeat):
        meanVal = mean(datMat[nonzero(~isnan(datMat[:,i].A))[0],i]) #values that are not NaN (a number)
        datMat[nonzero(isnan(datMat[:,i].A))[0],i] = meanVal  #set NaN values to mean
    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)

结果:

机器学习实战(十一)利用PCA来简化数据

结果说明:

我们会发现其中很多值都是 0吗?实 际 上 ,其中有超过 2 0 % 的特征值都是 0 。这就意味着这些特征都是其他特征的副本,也就是 说 ,它们可以通过其他特征来表示,而本身并没有提供额外的信息。

接 下 来 ,我们了解一下部分数值的数量级。最 前 面 15 个 值的 数量 级 大 于 105 ,实际上那以后 的 值 都 变 得 非 常 小 。这 就相 当 于 告 诉 我 们 只 有 部 分 重 要 特 征 ,重要特征的数目也很快就会下 降 。

最 后 ,我们可能会注意到有一些小的负值,它们主要源自数值误差应该四舍五入成 0 。

图13-4 中给出了总方差的百分比,可以看出来在开始的几个主成分之后,方差就会迅速下降。

机器学习实战(十一)利用PCA来简化数据

表 13-1 给出了这些主成分所对应的方差百分比和累积方差百分比。浏 览 “ 累积方差百分比( % )” 这一列就会注意到 , 前六个主成分就覆盖了数据 96.8% 的方 差 , 而前 20 个主成分覆盖了 99.3%的方差。这就表明了,如果保留前 6 个而去除后 584 个 主 成 分 ,我们就可以实现大概 100 : 1 的压缩比。另 外 ,由于舍弃了噪声的主成分,将后面的主成分去除便使得数据更加干净。

机器学习实战(十一)利用PCA来简化数据

于 是 ,我们可以知道在数据集的前面多个主成分中所包含的信息量。我们可以尝试不同的截断值来检验它们的性能。有些人使用能包含90%信息量的主成分数量, 而其他人使用前20个主成分。 我们无法精确知道所需要的主成分数目, 必须通过在实验中取不同的值来确定。有效的主成分数目则取决于数据集和具体应用。
上述分析能够得到所用到的主成分数目, 然后我们可以将该数目输人到PCA算法中, 最后得到约简后数据就可以在分类器中使用了。

13.4 总结

降维技术使得数据变得更易使用,并且能够去除数据中的噪声,使得其他机器学习任务更加精确。