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

在体育比赛中,人们面对的原本是百万像素的数据,但是只有球的三维位置才最重要,这就成为降维(dimensionlity reduction)。通常而言,我们在应用其他机器学习算法之前,必须先识别出其相关特征。
第一种降维称作主方法分析(Principal Component Analysis,PCA)。
第一个坐标值选择的是原始数据中方差最大的方向,第二个新坐标轴的选择和第一个坐标轴正交且具有最大方差的方向。
另一种降维技术是因子分析(Factor Analysis)。在因子分析中,我们假设在观察数据的生成一些观察不到的隐变量(latent variable)。假设观察数据是这些隐变量和某些噪声的线性组合。那么隐变量的数据可能比观察数据的数目少,也就是说通过隐变量可以实现数据的降维。
还有一种方法就是独立成分分析(Independent Component Analysis,ICA)。ICA假设数据是从N个数据源生成的,这一点和因子分析有些类似。假设数据为多个数据源的混合观察结果,这些数据源之间在统计上是互相独立的,而在PCA中之假设数据是不相关的。
在上述3种降维技术中,PCA的应用目前最为广泛,因此本章主要关注PCA。在下一节中,我们将会对PCA进行介绍,然后再通过一段Python代码来运行PCA。

主成分分析
优点:降低数据的复杂性,识别最重要的多个特征
缺点:不一定需要,且可能损失有用信息
适用数据类型:数据型数据

将数据转化成前N个主成分的伪代码大致如下:

去除平均值
计算协方差矩阵
计算协方差矩阵的特征值和特征向量
将特征值从打到小排序
保留最上面的N个特征向量
将数据转换到上述N个特征向量构建的新空间中

下面开始构建PCA算法

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)

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)            #从小到大排序
    eigValInd = eigValInd[:-(topNfeat+1):-1]  #逆序,从大到小
    redEigVects = eigVects[:,eigValInd]       
    lowDDataMat = meanRemoved * redEigVects#将数据转化到新的维度空间
    reconMat = (lowDDataMat * redEigVects.T) + meanVals
    return lowDDataMat, reconMat

我们在testSet.txt文件中加入一个由1000个数据点组成的数据集,开始进行PCA操作:

In [17]: import pca
    ...: dataMat = pca.loadDataSet('testSet.txt')
    ...: lowDMat, reconMat = pca.pca(dataMat, 1)
    ...: shape(lowDMat)
    ...: 
Out[17]: (1000L, 1L)

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()
    ...:

机器学习实战-利用PCA来简化数据_第1张图片
使用如下命令代替PCA调用,也会看到类似结果:

lowDMat, reconMat = pca.pca(dataMat, 2)

下面我们先处理一些异常值,用平均值代替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]) 
        datMat[nonzero(isnan(datMat[:,i].A))[0],i] = meanVal  #将所有nan置为平均值
    return datMat

PCA会给出数据中所包含的信息量。数据(data)和信息(information)之间具有巨大的差别。数据指的是接受的原始材料,其中包含噪声和不相关的信息。信息指数据中的相关部分。下面开始操作,首先将所有的NaN值替换为平均值:

In [36]: import pca
    ...: dataMat = pca.replaceNanWithMean()
    ...: 

接下来从pca()函数中借用一些代码来达到我们的目的,之所以借用是因为我们想了解中间结果而非最后输出结果,调用如下语句去除均值:

In [37]: meanVals = mean(dataMat, axis = 0)
    ...: meanRemoved = dataMat - meanVals
    ...:

然后计算协方差矩阵:

In [38]: covMat = cov(meanRemoved, rowvar=0)

最后对该矩阵进行特征值分析:

In [39]: eigVals,eigVects = linalg.eig(mat(covMat))
    ...: 
    ...: eigVals
    ...: 
Out[39]: 
array([ 53415197.85687517+0.j,  21746671.90465918+0.j,
         8248376.61529074+0.j, ...,         0.00000000+0.j,
               0.00000000+0.j,         0.00000000+0.j])

我们会发现超过20%的特征值都是0。这意味着这些特征都是其他特征的副本,也就是说,他们可以通过其他特征来表示,而本身并没有提供额外的信息。
接下来,我们了解一下部分数值的数量级。最前面15个值的数量级大于10的五次方,实际上那以后的值都变得非常小。这相当于告诉我们部分重要特征,重要特征的数目也很快就会下降。
最后,我们注意到一些负值,他们主要源于数值误差,应该四舍五入为0。

你可能感兴趣的:(机器学习实战-利用PCA来简化数据)