怎样用PCA技术简化数据,你造吗?-阿里云开发者社区

开发者社区> 天池大数据科研平台> 正文

怎样用PCA技术简化数据,你造吗?

简介: 本章中的PCA将所有的数据集都调入了内存,如果无法做到,就需要其他的方法来寻找其特征值。

文章转载自ApacheCN
作者:片刻


1、降维技术

一 场景

我们正通过电视观看体育比赛,在电视的显示器上有一个球。

显示器大概包含了100万像素点,而球则可能是由较少的像素点组成,例如说一千个像素点。

人们实时的将显示器上的百万像素转换成为一个三维图像,该图像就给出运动场上球的位置。

这个过程中,人们已经将百万像素点的数据,降至为三维。这个过程就称为降维(dimensionality reduction)。

二 数据显示

数据显示并非大规模特征下的唯一难题,对数据进行简化还有如下一系列的原因:

使得数据集更容易使用

降低很多算法的计算开销

去除噪音

使得结果易懂

三 适用范围

在已标注与未标注的数据上都有降维技术。

这里我们将主要关注未标注数据上的降维技术,将技术同样也可以应用于已标注的数据。

四 PCA降维技术

在以下3种降维技术中, PCA的应用目前最为广泛,因此本章主要关注PCA。

1、主成分分析(Principal Component Analysis, PCA)

通俗理解:就是找出一个最主要的特征,然后进行分析。

例如: 考察一个人的智力情况,就直接看数学成绩就行(存在:数学、语文、英语成绩)

2、因子分析(Factor Analysis)

通俗理解:将多个实测变量转换为少数几个综合指标。它反映一种降维的思想,通过降维将相关性高的变量聚在一起,从而减少需要分析的变量的数量,而减少问题分析的复杂性

例如: 考察一个人的整体情况,就直接组合3样成绩(隐变量),看平均成绩就行(存在:数学、语文、英语成绩)

应用的领域:社会科学、金融和其他领域

在因子分析中,我们

假设观察数据的成分中有一些观察不到的隐变量(latent variable)。

假设观察数据是这些隐变量和某些噪音的线性组合。

那么隐变量的数据可能比观察数据的数目少,也就说通过找到隐变量就可以实现数据的降维。

3、独立成分分析(Independ Component Analysis, ICA)

通俗理解:ICA 认为观测信号是若干个独立信号的线性组合,ICA 要做的是一个解混过程。

例如:我们去ktv唱歌,想辨别唱的是什么歌曲?ICA 是观察发现是原唱唱的一首歌【2个独立的声音(原唱/主唱)】。

ICA 是假设数据是从 N 个数据源混合组成的,这一点和因子分析有些类似,这些数据源之间在统计上是相互独立的,而在 PCA 中只假设数据是不 相关(线性关系)的。

同因子分析一样,如果数据源的数目少于观察数据的数目,则可以实现降维过程。

02、PCA

一 PCA概述

主成分分析(Principal Component Analysis, PCA):通俗理解:就是找出一个最主要的特征,然后进行分析。

二 PCA场景

例如: 考察一个人的智力情况,就直接看数学成绩就行(存在:数学、语文、英语成绩)

三 PCA原理

1、PCA 工作原理

找出第一个主成分的方向,也就是数据 方差最大 的方向。

找出第二个主成分的方向,也就是数据 方差次大 的方向,并且该方向与第一个主成分方向 正交(orthogonal 如果是二维空间就叫垂直)。

通过这种方式计算出所有的主成分方向。

通过数据集的协方差矩阵及其特征值分析,我们就可以得到这些主成分的值。

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

2、为什么正交?

正交是为了数据有效性损失最小

正交的一个原因是特征值的特征向量是正交的

例如下图:
image.png

3、PCA 优缺点

优点:降低数据的复杂性,识别最重要的多个特征。

缺点:不一定需要,且可能损失有用信息。

适用数据类型:数值型数据。

3、项目案例:对半导体数据进行降维处理

一 项目概述

半导体是在一些极为先进的工厂中制造出来的。设备的生命早期有限,并且花费极其巨大。

虽然通过早期测试和频繁测试来发现有瑕疵的产品,但仍有一些存在瑕疵的产品通过测试。

如果我们通过机器学习技术用于发现瑕疵产品,那么它就会为制造商节省大量的资金。

具体来讲,它拥有590个特征。我们看看能否对这些特征进行降维处理。

对于数据的缺失值的问题,我们有一些处理方法(参考第5章)

目前该章节处理的方案是:将缺失值NaN(Not a Number缩写),全部用平均值来替代(如果用0来处理的策略就太差劲了)。

二 开发流程

1、收集数据:提供文本文件

文件名:secom.data

文本文件数据格式如下:
image.png

2、准备数据:将value为NaN的求均值

def replaceNanWithMean():
    datMat = loadDataSet('db/13.PCA/secom.data', ' ')
    numFeat = shape(datMat)[1]
    for i in range(numFeat):
        # 对value不为NaN的求均值
        # .A 返回矩阵基于的数组
        meanVal = mean(datMat[nonzero(~isnan(datMat[:, i].A))[0], i])
        # 将value为NaN的值赋值为均值
        datMat[nonzero(isnan(datMat[:, i].A))[0],i] = meanVal
    return datMat

3、分析数据:统计分析 N 的阈值

image.png

4、PCA 数据降维

在等式 Av=λvAv=λv 中,v 是特征向量, 入是特征值。

表示 如果特征向量 v 被某个矩阵 A 左乘,那么它就等于某个标量 入 乘以 v.

幸运的是: Numpy 中有寻找特征向量和特征值的模块 linalg,它有 eig() 方法,该方法用于求解特征向量和特征值。

def pca(dataMat, topNfeat=9999999):
    """pca

    Args:
        dataMat   原数据集矩阵
        topNfeat  应用的N个特征
    Returns:
        lowDDataMat  降维后数据集
        reconMat     新的数据集空间
    """

    # 计算每一列的均值
    meanVals = mean(dataMat, axis=0)
    # print 'meanVals', meanVals

    # 每个向量同时都减去 均值
    meanRemoved = dataMat - meanVals
    # print 'meanRemoved=', meanRemoved

    # cov协方差=[(x1-x均值)*(y1-y均值)+(x2-x均值)*(y2-y均值)+...+(xn-x均值)*(yn-y均值)+]/(n-1)
    '''
    方差:(一维)度量两个随机变量关系的统计量
    协方差: (二维)度量各个维度偏离其均值的程度
    协方差矩阵:(多维)度量各个维度偏离其均值的程度

    当 cov(X, Y)>0时,表明X与Y正相关;(X越大,Y也越大;X越小Y,也越小。这种情况,我们称为“正相关”。)
    当 cov(X, Y)<0时,表明X与Y负相关;
    当 cov(X, Y)=0时,表明X与Y不相关。
    '''
    covMat = cov(meanRemoved, rowvar=0)

    # eigVals为特征值, eigVects为特征向量
    eigVals, eigVects = linalg.eig(mat(covMat))
    # print 'eigVals=', eigVals
    # print 'eigVects=', eigVects
    # 对特征值,进行从小到大的排序,返回从小到大的index序号
    # 特征值的逆序就可以得到topNfeat个最大的特征向量
    '''
    >>> x = np.array([3, 1, 2])
    >>> np.argsort(x)
    array([1, 2, 0])  # index,1 = 1; index,2 = 2; index,0 = 3
    >>> y = np.argsort(x)
    >>> y[::-1]
    array([0, 2, 1])
    >>> y[:-3:-1]
    array([0, 2])  # 取出 -1, -2
    >>> y[:-6:-1]
    array([0, 2, 1])
    '''
    eigValInd = argsort(eigVals)
    # print 'eigValInd1=', eigValInd

    # -1表示倒序,返回topN的特征值[-1 到 -(topNfeat+1) 但是不包括-(topNfeat+1)本身的倒叙]
    eigValInd = eigValInd[:-(topNfeat+1):-1]
    # print 'eigValInd2=', eigValInd
    # 重组 eigVects 最大到最小
    redEigVects = eigVects[:, eigValInd]
    # print 'redEigVects=', redEigVects.T
    # 将数据转换到新空间
    # --- (1567, 590) (590, 20)
    # print "---", shape(meanRemoved), shape(redEigVects)
    lowDDataMat = meanRemoved * redEigVects
    reconMat = (lowDDataMat * redEigVects.T) + meanVals
    # print 'lowDDataMat=', lowDDataMat
    # print 'reconMat=', reconMat
    return lowDDataMat, reconMat
##项目完整代码:

#!/usr/bin/python
# coding:utf8

'''
Created on Jun 1, 2011
Update  on 2017-12-20
@author: Peter Harrington/片刻
《机器学习实战》更新地址:https://github.com/apachecn/MachineLearning
'''
from numpy import *
import matplotlib.pyplot as plt
print(__doc__)


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]
    #注意这里和python2的区别,需要在map函数外加一个list(),否则显示结果为 map at 0x3fed1d0
    return mat(datArr)


def pca(dataMat, topNfeat=9999999):
    """pca

    Args:
        dataMat   原数据集矩阵
        topNfeat  应用的N个特征
    Returns:
        lowDDataMat  降维后数据集
        reconMat     新的数据集空间
    """

    # 计算每一列的均值
    meanVals = mean(dataMat, axis=0)
    # print('meanVals', meanVals)

    # 每个向量同时都减去 均值
    meanRemoved = dataMat - meanVals
    # print('meanRemoved=', meanRemoved)

    # cov协方差=[(x1-x均值)*(y1-y均值)+(x2-x均值)*(y2-y均值)+...+(xn-x均值)*(yn-y均值)+]/(n-1)
    '''
    方差:(一维)度量两个随机变量关系的统计量
    协方差: (二维)度量各个维度偏离其均值的程度
    协方差矩阵:(多维)度量各个维度偏离其均值的程度

    当 cov(X, Y)>0时,表明X与Y正相关;(X越大,Y也越大;X越小Y,也越小。这种情况,我们称为“正相关”。)
    当 cov(X, Y)<0时,表明X与Y负相关;
    当 cov(X, Y)=0时,表明X与Y不相关。
    '''
    covMat = cov(meanRemoved, rowvar=0)

    # eigVals为特征值, eigVects为特征向量
    eigVals, eigVects = linalg.eig(mat(covMat))
    # print('eigVals=', eigVals)
    # print('eigVects=', eigVects)
    # 对特征值,进行从小到大的排序,返回从小到大的index序号
    # 特征值的逆序就可以得到topNfeat个最大的特征向量
    '''
    >>> x = np.array([3, 1, 2])
    >>> np.argsort(x)
    array([1, 2, 0])  # index,1 = 1; index,2 = 2; index,0 = 3
    >>> y = np.argsort(x)
    >>> y[::-1]
    array([0, 2, 1])
    >>> y[:-3:-1]
    array([0, 2])  # 取出 -1, -2
    >>> y[:-6:-1]
    array([0, 2, 1])
    '''
    eigValInd = argsort(eigVals)
    # print('eigValInd1=', eigValInd)

    # -1表示倒序,返回topN的特征值[-1 到 -(topNfeat+1) 但是不包括-(topNfeat+1)本身的倒叙]
    eigValInd = eigValInd[:-(topNfeat+1):-1]
    # print('eigValInd2=', eigValInd)
    # 重组 eigVects 最大到最小
    redEigVects = eigVects[:, eigValInd]
    # print('redEigVects=', redEigVects.T)
    # 将数据转换到新空间
    # print( "---", shape(meanRemoved), shape(redEigVects))
    lowDDataMat = meanRemoved * redEigVects
    reconMat = (lowDDataMat * redEigVects.T) + meanVals
    # print('lowDDataMat=', lowDDataMat)
    # print('reconMat=', reconMat)
    return lowDDataMat, reconMat


def replaceNanWithMean():
    datMat = loadDataSet('input/13.PCA/secom.data', ' ')
    numFeat = shape(datMat)[1]
    for i in range(numFeat):
        # 对value不为NaN的求均值
        # .A 返回矩阵基于的数组
        meanVal = mean(datMat[nonzero(~isnan(datMat[:, i].A))[0], i])
        # 将value为NaN的值赋值为均值
        datMat[nonzero(isnan(datMat[:, i].A))[0],i] = meanVal
    return datMat


def show_picture(dataMat, reconMat):
    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()


def analyse_data(dataMat):
    meanVals = mean(dataMat, axis=0)
    meanRemoved = dataMat-meanVals
    covMat = cov(meanRemoved, rowvar=0)
    eigvals, eigVects = linalg.eig(mat(covMat))
    eigValInd = argsort(eigvals)

    topNfeat = 20
    eigValInd = eigValInd[:-(topNfeat+1):-1]
    cov_all_score = float(sum(eigvals))
    sum_cov_score = 0
    for i in range(0, len(eigValInd)):
        line_cov_score = float(eigvals[eigValInd[i]])
        sum_cov_score += line_cov_score
        '''
        我们发现其中有超过20%的特征值都是0。
        这就意味着这些特征都是其他特征的副本,也就是说,它们可以通过其他特征来表示,而本身并没有提供额外的信息。

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

        最后,我们可能会注意到有一些小的负值,他们主要源自数值误差应该四舍五入成0.
        '''
        print('主成分:%s, 方差占比:%s%%, 累积方差占比:%s%%' % (format(i+1, '2.0f'), format(line_cov_score/cov_all_score*100, '4.2f'), format(sum_cov_score/cov_all_score*100, '4.1f')))


if __name__ == "__main__":
    # # 加载数据,并转化数据类型为float
    # dataMat = loadDataSet('input/13.PCA/testSet.txt')
    # # 只需要1个特征向量
    # lowDmat, reconMat = pca(dataMat, 1)
    # # 只需要2个特征向量,和原始数据一致,没任何变化
    # # lowDmat, reconMat = pca(dataMat, 2)
    # # print(shape(lowDmat))
    # show_picture(dataMat, reconMat)

    # 利用PCA对半导体制造数据降维
    dataMat = replaceNanWithMean()
    print(shape(dataMat))
    # 分析数据
    analyse_data(dataMat)
    # lowDmat, reconMat = pca(dataMat, 20)
    # print(shape(lowDmat))
    # show_picture(dataMat, reconMat)

4、要点补充

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

降维往往作为预处理步骤,在数据应用到其他算法之前清洗数据。

比较流行的降维技术: 独立成分分析、因子分析 和 主成分分析, 其中又以主成分分析应用最广泛。

本章中的PCA将所有的数据集都调入了内存,如果无法做到,就需要其他的方法来寻找其特征值。

版权声明:如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:developerteam@list.alibaba-inc.com 进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
天池大数据科研平台
使用钉钉扫一扫加入圈子
+ 订阅

于阿里云的开放数据处理服务ODPS

官方博客
官网链接