用python实现主成分分析(PCA)

     阅读:30

python应用实例:如何用python实现主成分分析

主成分分析(Principal Component Analysis,PCA)是一种统计方法。通过正交变换将一组可能存在相关性的变量转换为一组线性不相关的变量,转换后的这组变量叫主成分。

背景

在许多机器学习、深度学习的应用中,往往需要处理大量样本或大的矩阵,多变量大样本无疑会为研究和应用提供丰富的信息,但也在一定程度上增加了数据采集的工作量。更重要的是在多数情况下,许多变量之间可能存在相关性,从而增加了问题分析的复杂性,同时对分析带来不便。如果分别对每个指标进行分析,分析往往是孤立的,而不是综合的。而盲目减少指标又会损失很多信息,且容易产生错误的结论。因此需要找到一个合理有效的方法,在减少需要分析指标或维度的同时,尽量减少原指标所含信息的损失,以达到对所收集数据进行全面分析的目的。由于各变量间存在一定的相关关系,因此有可能用较少的综合指标分别存储变量的各类信息。主成分分析就属于这类降维的方法。

如何实现以上目标呢?这里我们简要说明一下原理,然后使用Python来实现,至于详细的推导过程,大家可以参考相关书籍或网上别的资料。

问题:设在n维空间中有m个样本点:{x1,x2,…, xm},假设m比较大,需要对这些点进行压缩,使其投影到k维空间中,其中k<n,同时使损失的信息最小。

该如何实现呢?以下简要说明以下思路。

设投影到k维空间后的新坐标系为{w1,w2,…,2n},其中,在这里插入图片描述,即满足:在这里插入图片描述
设矩阵W={w1,w2,…,wk}是一个大小为nxk维的正交矩阵,它是一个投影矩阵。X={x1,x2,…,xm}是训练数据集,为n×m维的矩阵,由矩阵乘法的定义可知,投影到k维空间的点的坐标为在这里插入图片描述

利用该坐标系重构数据,即把数据集Z从k维空间重新映射回n维空间,得到新的坐标点:在这里插入图片描述

要使信息损失最小,一种合理的设想就是重构后的点X*与原来的数据点之间的距离最小,据此,PCA可转换为求带约束的最优化问题:在这里插入图片描述
在这里插入图片描述

根据范数与矩阵迹的关系,上式可进一步简化为:在这里插入图片描述
最后可以化简为:
在这里插入图片描述
(3.21)
在这里插入图片描述

然后利用拉格朗日乘子法求解(3.21)式的最优解:在这里插入图片描述
(3.22)

最后对(3.22)式两端对w求导,并令导数为0,化简后就可得到:

在这里插入图片描述(3.23)

由(3.23)式可知,W是由协方差矩阵XX^T的特征向量构成的特征矩阵,利用特征值分解的方法就可求出W。

以下我们用python具体实现一个PCA实例。以iris作为数据集,该数据集可以通过load_iris自动下载。

iris数据集简介

Iris数据集是常用的分类实验数据集,由Fisher在1936年收集整理。iris也称鸢尾花数据集。数据集包含150个数据集,分为3类,每类50个数据,每个数据包含4个属性。可通过花萼长度、花萼宽度、花瓣长度、花瓣宽度4个属性预测鸢尾花卉属于(Setosa、Versicolour、Virginica)三类中的哪一类。

算法的主要步骤

算法的具体步骤如下:
1)对向量X进行去中心化。
2)计算向量X的协方差矩阵,自由度可以选择0或者1。
3)计算协方差矩阵的特征值和特征向量。
4)选取最大的k个特征值及其特征向量。
5)用X与特征向量相乘。

代码实现

下面展示 python代码实现

// 用python实现主成分分析(PCA)
import numpy as np
from numpy.linalg import eig
from sklearn.datasets import load_iris
def pca(X,k):
    X = X - X.mean(axis = 0) #向量X去中心化
    X_cov = np.cov(X.T, ddof = 0) #计算向量X的协方差矩阵,自由度可以选择01
    eigenvalues,eigenvectors = eig(X_cov) #计算协方差矩阵的特征值和特征向量
    klarge_index = eigenvalues.argsort()[-k:][::-1] #选取最大的K个特征值及其特征向量
    k_eigenvectors = eigenvectors[klarge_index] #用X与特征向量相乘
    return np.dot(X, k_eigenvectors.T)
iris = load_iris()
X = iris.data
k = 2
X_pca = pca(X, k)
print(X_pca)

运行结果:
pydev debugger: process 15912 is connecting

Connected to pydev debugger (build 193.6911.25)
[[ 4.97868859e-01 -1.35075351e+00]
[ 7.53885926e-01 -9.68768289e-01]
[ 6.08493838e-01 -1.15768716e+00]
[ 5.21608086e-01 -9.56636595e-01]
[ 3.96071322e-01 -1.41531740e+00]
[ 2.32137811e-01 -1.55274621e+00]
[ 4.14383159e-01 -1.26744842e+00]
[ 4.69186091e-01 -1.20949403e+00]
[ 6.38851507e-01 -8.53490888e-01]
[ 5.98475344e-01 -9.50021039e-01]
[ 4.16764097e-01 -1.46235147e+00]
[ 3.38705788e-01 -1.13279845e+00]
[ 6.86198547e-01 -9.28343727e-01]
[ 6.80114207e-01 -1.06545572e+00]
[ 5.38951057e-01 -1.89458215e+00]
[ 1.28665373e-01 -2.06276585e+00]
[ 4.64949751e-01 -1.79191054e+00]
[ 5.29417578e-01 -1.38272582e+00]
[ 3.74663946e-01 -1.47311451e+00]
[ 2.74237961e-01 -1.54198317e+00]
[ 4.97334758e-01 -1.12372087e+00]
[ 3.71445558e-01 -1.50093933e+00]
[ 4.84328626e-01 -1.62067273e+00]
[ 5.49223815e-01 -1.12126490e+00]
[ 1.64096833e-01 -9.53425196e-01]
[ 6.73618615e-01 -8.57638374e-01]
[ 4.74080545e-01 -1.21364757e+00]
[ 4.75804533e-01 -1.29941468e+00]
[ 5.99666395e-01 -1.28618962e+00]
[ 4.33884883e-01 -9.78313907e-01]
[ 5.35682419e-01 -9.13750015e-01]
[ 6.76838167e-01 -1.30724766e+00]
[ 5.03025506e-02 -1.70553923e+00]
[ 1.82811355e-01 -1.89567552e+00]
[ 6.30024064e-01 -9.81993349e-01]
[ 7.75112801e-01 -1.24283499e+00]
[ 7.00626480e-01 -1.44435360e+00]
[ 3.28383944e-01 -1.37489284e+00]
[ 6.31395615e-01 -9.86298115e-01]
[ 5.05324751e-01 -1.21794628e+00]
[ 5.51481904e-01 -1.43406465e+00]
[ 1.15869513e+00 -5.15609672e-01]
[ 5.00077861e-01 -1.13233040e+00]
[ 4.71519106e-01 -1.35060833e+00]
[ 7.29747402e-02 -1.33479114e+00]
[ 7.49295986e-01 -9.92288348e-01]
[ 1.84486257e-01 -1.45021977e+00]
[ 5.14152194e-01 -1.08944382e+00]
[ 3.80625438e-01 -1.45389922e+00]
[ 5.93047954e-01 -1.19626897e+00]
[-1.60633863e-01 2.97140160e-01]
[-2.29511129e-01 1.96299192e-01]
[-2.15970896e-01 4.66218410e-01]
[ 2.64088320e-01 6.94503952e-01]
[ 1.10600536e-02 5.39702597e-01]
[-2.82943673e-01 6.11474146e-01]
[-4.16165916e-01 2.19345155e-01]
[ 2.94372226e-01 3.49580667e-01]
[-8.15576029e-02 5.22178823e-01]
[-1.72114620e-02 3.36032738e-01]
[ 4.76740423e-01 7.52775155e-01]
[-1.04277715e-01 2.05219487e-01]
[ 4.15794335e-01 8.21175769e-01]
[-2.88905165e-01 5.92258853e-01]
[ 1.39085657e-01 8.79050724e-03]
[-2.87820084e-02 2.16139809e-01]
[-3.87302648e-01 4.09949490e-01]
[-4.29803543e-02 5.32790638e-01]
[ 3.54800324e-01 9.43365130e-01]
[ 1.64014771e-01 5.44172951e-01]
[-4.90167222e-01 3.22016767e-01]
[ 1.52625889e-01 2.78709726e-01]
[-3.88495887e-02 9.55028780e-01]
[-2.86343726e-01 7.29219617e-01]
[ 2.07740341e-02 3.59710077e-01]
[ 7.38209509e-04 2.97608203e-01]
[-2.84786584e-02 6.65900320e-01]
[-2.17694884e-01 5.51985519e-01]
[-1.77089134e-01 4.49156628e-01]
[ 3.35757774e-01 2.55512534e-01]
[ 2.51737974e-01 5.65850263e-01]
[ 2.78392240e-01 5.38031490e-01]
[ 1.36523055e-01 3.49263851e-01]
[-3.63440572e-01 9.21963103e-01]
[-4.59579966e-01 4.26853993e-01]
[-4.73834801e-01 5.21036002e-02]
[-1.71842245e-01 3.63540747e-01]
[ 3.20385653e-01 8.66050272e-01]
[-2.17588146e-01 2.34729779e-01]
[ 1.32770565e-01 5.48471665e-01]
[-1.97248972e-01 7.46592164e-01]
[-2.96361057e-01 4.59451626e-01]
[ 1.43978947e-01 4.82071077e-01]
[ 3.96169762e-01 4.14144559e-01]
[-7.88144999e-02 5.13569292e-01]
[-2.71201191e-01 3.18040921e-01]
[-1.73993595e-01 3.59084754e-01]
[-5.15032842e-02 3.76614580e-01]
[ 5.07148341e-01 4.83144609e-02]
[-5.01317327e-02 3.72309814e-01]
[-8.88866249e-01 7.08878441e-01]
[-3.41071732e-01 8.42950674e-01]
[-4.70772237e-01 9.28407019e-01]
[-6.14259835e-01 9.85584856e-01]
[-5.97852487e-01 8.87357134e-01]
[-6.97499837e-01 1.30468334e+00]
[-2.48881438e-01 7.70251347e-01]
[-6.60294139e-01 1.31959992e+00]
[-3.23475660e-01 1.36342259e+00]
[-8.18797933e-01 4.73550831e-01]
[-3.84846784e-01 3.86731887e-01]
[-2.40645747e-01 9.11819332e-01]
[-3.46376274e-01 7.14599441e-01]
[-1.56140932e-01 9.05671819e-01]
[-2.48987013e-01 6.10072979e-01]
[-4.42745256e-01 4.18849373e-01]
[-5.49438409e-01 8.35873126e-01]
[-1.21328646e+00 7.39920716e-01]
[-5.10237186e-01 1.70372429e+00]
[-8.49192003e-03 1.25922505e+00]
[-4.94863900e-01 6.15752448e-01]
[-3.31053238e-01 6.35284557e-01]
[-6.19795128e-01 1.53402677e+00]
[-7.55211851e-02 7.13079562e-01]
[-6.95897534e-01 6.23585428e-01]
[-7.18800475e-01 9.29630495e-01]
[-1.19115736e-01 5.88724587e-01]
[-3.44775135e-01 5.10935634e-01]
[-4.17816141e-01 9.54231817e-01]
[-5.34174189e-01 1.02002524e+00]
[-4.10541914e-01 1.23260934e+00]
[-1.02949763e+00 6.07587585e-01]
[-3.86267422e-01 9.22259506e-01]
[-3.52232190e-01 8.55562515e-01]
[-6.15755399e-01 1.34942703e+00]
[-3.07248813e-01 9.33331056e-01]
[-7.53261905e-01 4.28670276e-01]
[-6.51235945e-01 7.71309234e-01]
[-3.22710809e-01 4.59596802e-01]
[-3.17693506e-01 5.73339963e-01]
[-4.11730637e-01 6.13909701e-01]
[-7.99871124e-02 3.30022093e-01]
[-3.41071732e-01 8.42950674e-01]
[-6.47408530e-01 7.43786865e-01]
[-5.69702657e-01 4.95696187e-01]
[-1.44808539e-01 4.79733823e-01]
[ 2.91423033e-02 8.86930621e-01]
[-3.11732015e-01 5.92555257e-01]
[-7.04543313e-01 3.49512672e-01]
[-5.33458423e-01 6.47422303e-01]]

Process finished with exit code 0

查看各特征值的贡献率

我们看一下各特征值的贡献率:

python代码实现:

// An highlighted block
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()

下图为代码运行结果,各特征值的贡献率示意图:
在这里插入图片描述
各特征值的贡献率如图所示,可以看出,前两个特征值的方差贡献率超过95%,所以k取2有其合理性。

以上内容from《Python深度学习:基于TensorFlow》。