《机器学习实战》利用PCA来简化数据

版权声明:【http://thinkgamer.cn】 https://blog.csdn.net/Gamer_gyt/article/details/51418069

=====================================================================

  《机器学习实战》系列博客是博主阅读《机器学习实战》这本书的笔记也包含一些其他python实现的机器学习算法

    github 源码同步:https://github.com/Thinkgamer/Machine-Learning-With-Python

   算法实现均采用Python              如需转载请注明出处,谢谢

=====================================================================

对数据简化的原因

1:使得数据更易使用

2:降低很多算法的计算开销

3:去除噪声

4:使得结果易懂


降维方法

1:主成分分析法( PrincipalComponentAnalysis, P C A )

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


2:因子分析(Factor Analysis)

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


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

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


PCA降维技术(应用最广泛)

                                                     

                           覆盖整个数据集的三条直线,其中直线 8 最长,并给出了数据集中差异化最大的方向


在PCA中我们对数据进行了旋转,该旋转的过程取决与数据本身,如上图,在A,B,C三条直线中。B直线覆盖数据的范围最广,那么把第一条坐标轴旋转到B直线的位置,此时覆盖数据的方差最大,数据的最大放方差给出了数据的最重要的信息

选定第一条坐标轴之后,假如该坐标轴与第一条坐标轴垂直, 它就是覆盖数据次大差异性的坐标轴。这里更严谨的说法就是正交(orthogonal)当然 ,在二维平面下,垂直和正交是一回事,直线 C 就是第二条坐标轴。利用PCA我们将数据坐标轴旋转至数据角度上的那些最重要的方向。

我们已经实现了坐标轴的旋转,接下来开始讨论降维,坐标轴的旋转并没有减少数据的维度。

                                              

                  二维空间的 3 个类别。当在该数据集上应用PCA时,就可以去掉一维,从而使得该分类问题变得更容易处理


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

        通过PCA进行降维处理,我们就可以同时获得 SVM和决策树的优点: 一 方 面 ,得到了和决策树一样简单的分类器,同时分类间隔和 SVM一样好,如上图,其中的数据来自于上面的图并经 过PCA转换之后绘制而成的,如果仅使用原始数据,那么这里的间隔会比决策树的间隔更大。 另 外 ,由于只需要考虑一维信息,因此数据就可以通过比 S V M 简单得多的很容易采用的规则进行区分 。

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

下面我们用代码实现PCA:

<span style="font-size:18px;"><span style="font-size:14px;">#-*-coding:utf8-*-
'''
Created on 2016-5-15

@author: thinkgamer
'''
from numpy import *

def loadDataSet(filename,delim = "\t"):
    fr = open(filename)
    stringArr = [line.strip().split(delim) for line in fr.readlines()]
    datArr = [map(float, line) for line in stringArr]
    return mat(datArr)

#dataMat对应数据集,N个特征
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

#测试
dataMat = loadDataSet("testSet.txt")
lowDMat, reconMat = pca(dataMat,1)
print shape(lowDMat)

#show
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' )</span>
<span style="font-size:14px;">plt.show() </span></span>

print的结果为:

(1000,1)

画图:


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


<span style="font-size:18px;"><span style="font-size:14px;">#将NaN替换成平均值函数
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

#加载数据               
dataMat = replaceNanWithMean()
#去除均值
meanVals = mean(dataMat, axis=0)
meanRemoved = dataMat - meanVals        
#计算协方差               
covMat = cov(meanRemoved, rowvar=0)

#特征值分析
eigVals,   eigVects = linalg.eig(mat(covMat))               
print eigVals            </span>   </span>

输出结果为:

数据说明:

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

        接 下 来 ,我们了解一下部分数值的数量级。最 前 面 15 个 值的 数量 级 大 于 105 ,实际上那以后 的 值 都 变 得 非 常 小 。这 就相 当 于 告 诉 我 们 只 有 部 分 重 要 特 征 ,重要特征的数目也很快就会下 降 。
        最 后 ,我们可能会注意到有一些小的负值,它们主要源自数值误差应该四舍五入成 0 。

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

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

没有更多推荐了,返回首页