主成分分析(Principal Component Analysis,PCA)是一种统计方法。通过正交变换将一组可能存在相关性的变量转换为一组线性不相关的变量,转换后的这组变量叫主成分。
在许多机器学习、深度学习的应用中,往往需要处理大量样本或大的矩阵,多变量大样本无疑会为研究和应用提供丰富的信息,但也在一定程度上增加了数据采集的工作量。更重要的是,在多数情况下,许多变量之间可能存在相关性,从而增加了问题分析的复杂性,同时对分析带来不便。如果分别对每个指标进行分析,分析往往是孤立的,而不是综合的。而盲目减少指标又会损失很多信息,且容易产生错误的结论。因此需要找到一个合理有效的方法,在减少需要分析指标或维度的同时,尽量减少原指标所含信息的损失,以达到对所收集数据进行全面分析的目的。由于各变量间存在一定的相关关系,因此有可能用较少的综合指标分别存储变量的各类信息。主成分分析就属于这类降维的方法。
如何实现以上目标呢?这里我们简要说明一下原理,然后使用Python来实现,至于详细的推导过程,大家可参考相关书籍或网上资料。
问题: 设在n维空间中有m个样本点:{x 1 ,x 2 ,…,x m },假设m比较大,需要对这些点进行压缩,使其投影到k维空间中,其中k<n,同时使损失的信息最小。
该如何实现呢?以下简要说明一下思路。
设投影到k维空间后的新坐标系为{w 1 ,w 2 ,…,w n },其中w i ∈R n ,w i 是标准的正交基向量,即满足:
设矩阵W={w 1 ,w 2 ,…,w k }是一个大小为n×k维的正交矩阵,它是一个投影矩阵。X={x 1 ,x 2 ,…,x m }是训练数据集,为n×m维的矩阵,由矩阵乘法的定义可知,投影到k维空间的点的坐标为Z=W T X。
利用该坐标系重构数据,即把数据集Z从k维空间重新映射回n维空间,得到新的坐标点:X*=WZ=WW T X。
要使信息损失最小,一种合理的设想就是重构后的点X*与原来的数据点之间距离最小,据此,PCA可转换为求带约束的最优化问题:
根据范数与矩阵迹的关系(3.18),上式可进一步简化为:
最后可以化简为:
然后,利用拉格朗日乘子法求解(3.21)式的最优解:
最后对(3.22)式两端对w求导,并令导数为0,化简后就可得到:
由(3.23)式可知,W是由协方差矩阵XX T 的特征向量构成的特征矩阵,利用特征值分解的方法就可求出W。
以下我们用Python具体实现一个PCA实例。以iris作为数据集,该数据集可以通过load_iris自动下载。
Iris数据集是常用的分类实验数据集,由Fisher在1936年收集整理。iris也称鸢尾花卉数据集。数据集包含150个数据集,分为3类,每类50个数据,每个数据包含4个属性。可通过花萼长度、花萼宽度、花瓣长度、花瓣宽度4个属性预测鸢尾花卉属于(Setosa、Versicolour、Virginica)三类中的哪一类。
算法的具体步骤如下:
1)对向量X进行去中心化。
2)计算向量X的协方差矩阵,自由度可以选择0或者1。
3)计算协方差矩阵的特征值和特征向量。
4)选取最大的k个特征值及其特征向量。
5)用X与特征向量相乘。
from sklearn.datasets import load_iris import numpy as np from numpy.linalg import eig def pca(X, k): # Standardize by remove average X = X - X.mean(axis = 0) # Calculate covariance matrix: X_cov = np.cov(X.T, ddof = 0) # Calculate eigenvalues and eigenvectors of covariance matrix eigenvalues, eigenvectors = eig(X_cov) # top k large eigenvectors klarge_index = eigenvalues.argsort()[-k:][::-1] k_eigenvectors = eigenvectors[klarge_index] return np.dot(X, k_eigenvectors.T) iris = load_iris() X = iris.data k = 2 #选取贡献最大的前2个特征 X_pca = pca(X, k)
我们看一下各特征值的贡献率:
import numpy as np import seaborn as sns import matplotlib.pyplot as plt from sklearn.datasets import load_iris from numpy.linalg import eig %matplotlib inline iris = load_iris() X = iris.data X = X - X.mean(axis = 0) # 计算协方差矩阵 X_cov = np.cov(X.T, ddof = 0) #计算协方差矩阵的特征值和特征向量 eigenvalues, eigenvectors = eig(X_cov) tot=sum(eigenvalues) var_exp=[(i / tot) for i in sorted(eigenvalues,reverse=True)] cum_var_exp=np.cumsum(var_exp) plt.bar(range(1,5),var_exp,alpha=0.5,align='center',label='individual var') plt.step(range(1,5),cum_var_exp,where='mid',label='cumulative var') plt.ylabel('variance rtion') plt.xlabel('principal components') plt.legend(loc='best') plt.show()
各特征值的贡献率如图3-1所示,可以看出,前两个特征值的方差贡献率超过95%,所以k取2有其合理性。
图3-1 各特征值的贡献率示意图