您的位置:首页 > 其它

【机器学习】主成分分析

2016-08-07 15:28 323 查看
前言:

前面我们已经分析了无监督学习中的聚类问题,现在把目光移向无监督学习的另一类重要问题——降维。想象一下这样的场景:我们通过电视机收看足球比赛。显示器大概包含100万像素,而球可能是较少像素组成的。在这个场景中,我们面对的原本是百万像素的数据,但是只有球的三维位置才最重要,因为三维图像才是最符合人类大脑的思维。这个时候就已经使用到了降维(dimensionalty reduction)技术。在当今的大数据时代,不仅数据量非常多,数据的维数也非常多,如何把数据可视化也是一个重要的课题。按照人类思维,我们最多只能看到三维的数据,三维以上的超空间数据只能用数学公式描述了。另外,很多时候我们并不需要关注数据的所有特征,往往只有其中几个特征对我们的决策是有帮助的,对数据进行简化还出于降低算法的计算开销的目的。降维的方法主要有三种:第一种降维的方法称为主成分分析(Principal Component Analysis, PCA)。这种方法把数据从原来的坐标系转换到一个新的坐标系,坐标系的方向要根据数据的方差决定。第二种降维方法是因子分析(Factor Analysis)。在因子分析中,假设数据是隐变量和某些噪声的线性组合,隐变量的数据可能比观察数据少,它的任务就是找出这些隐变量。第三种降维方法是独立成分分析(Independent Component Analysis)。ICA假设数据是从N个数据源生成的,原始数据是多个数据源的混合观察结果。如果数据源的数目少于观察数据的数目,也可以实现降维。PCA的最简单的一种降维算法,应用也最为广泛。因此本文介绍PCA算法。

一、问题引入

课程中举了一个直升飞机驾驶员的例子。每个驾驶员都有两个属性值:驾驶员的技能评估和驾驶员对飞行的享受程度。根据已有数据将这两个数据使用坐标图表示:



从图中得知,这两种属性是强相关的。u1方向是数据的相关性,称为“主方向”,u2方向则是噪声。我们表示数据的时候只需要用u1方向的坐标轴即可,数据则从二维降到了一维。那么,PCA的任务就是找到这个u1方向。

二、问题分析

1.数据预处理

运行PCA算法之前,一般都需要对数据进行预处理。因为不同维度的数据的数量级可能不同(比如人的体重(kg)和身高(m)通常就不是同一个数量级的),数量级大的就会对模型参数的影响比较大,所以我们必须赋予数据同样的权重。预处理的一般步骤如下:

(1)令


(2)用

来替代


(3)令


(4)使用

来替代


2.PCA模型的建立

PCA的任务是寻找一个主方向即向量u,使得投影点的方差最大化。如下图:



直观意义就是尽可能使投影点分散。下图的效果就十分不理想:



这种情况下,投影到子空间的数据方差很小,损失了其它维中的信息,可以看出你无法得知数据点在横轴原来是怎么分布的。因此,我们要做的就是使方差在子空间中最大化。下面给出主方向的数学定义:



为数据集中的点,u是要求解得单位向量,那么方差最大化可以形式化表示为:



注意到,我们已经对数据进行归一化预处理,投影点的均值为0,因此在计算方差的时候直接平方。该公式有一个约束条件:

。之后又可以使出拉格朗日函数求解了,设拉格朗日函数如下:



对u求偏导数,得:



令导数等于0,可知u就是协方差矩阵Σ(

)的特征向量(关于特征向量和特征值的详细概念参考线性代数课本,在Matlab或Python中使用eig函数求得)。最后,降维后的数据可以用如下表达式表达:



3.奇异值分解(SVD)

听说这个属于研究生课程里矩阵论的内容。SVD是PCA的另一种实现(在Matlab或Python中使用svd函数实现)。上面实现PCA的方法是先求协方差矩阵,然后对其求特征向量和特征值。这样做的缺点是,协方差矩阵的维度太大(n×n),在协方差矩阵上求特征值,计算量呈平方级增长,而SVD求解特征向量无需耗费大计算量。SVD的基本公式为:

,其中

,且都是对称矩阵。U的列向量即是

的特征向量,令



则协方差矩阵

,此时U恰好就是PCA的解。关于SVD,还有另一个很重要的应用:推荐系统。以后的博文中会介绍。

三、代码实现(Python)

(1)导入数据:

def loadDataSet(fileName):
dataMat = []
fr = open(fileName)
for line in fr.readlines():
curLine = line.strip().split('\t')
dataMat.append([float(curLine[0]), float(curLine[1])])
return mat(dataMat)


(2)数据预处理:

def preProcess(datMat):
mu = mean(datMat, axis = 0)
dataMat = datMat - mu
sigma = std(dataMat, axis = 0)
dataMat = dataMat / sigma
return dataMat


(3)主算法:

## 对协方差矩阵求特征值和特征向量
def pca(dataMat):
covMat = cov(dataMat, rowvar = 0)
val, u = linalg.eig(mat(covMat))
return u
## 对协方差矩阵求SVD
def pca(dataMat):
[m, n] = shape(dataMat)
sigma = dataMat.T * dataMat / m
[U, S, V] = linalg.svd(sigma)
return U, S


(4)数据投影及恢复:

def projectData(X, U, K):
Z = X * U[:, 0:K]
return Z

def recoverData(Z, U, K):
X_rec = Z * U[:, 0:K].T
return X_rec


(5)绘图:

dataMat = pca.loadDataSet('testSet.txt')
K = 1
## SVD
# dataMat = pcaSVD.preProcess(dataMat)
# U, S = pcaSVD.pca(dataMat)
# projectMat = pcaSVD.projectData(dataMat, U, K)
# recoverMat = pcaSVD.recoverData(projectMat, U, K)
## eig
dataMat = pca.preProcess(dataMat)
U = pca.pca(dataMat)
projectMat = pca.projectData(dataMat, U, K)
recoverMat = pca.recoverData(projectMat, U, K)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.scatter(dataMat[:,0], dataMat[:,1], marker='^', s=90, c='blue')
ax.scatter(recoverMat[:,0], recoverMat[:,1], marker='o', s=50, c='red')
plt.show()


两种方法的绘图效果一样:



我们成功把数据降到了一维。

四、总结

PCA的应用非常广泛,可以用于数据压缩与可视化,预处理和降噪等。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐