关于PCA(主成分分析,Principal components analysis),这里有非常通俗易懂的文章解释:主成份分析(PCA)最详细和全面的诠释

<http://mp.weixin.qq.com/s?__biz=MjM5MTgyNTk1NA==&mid=2649907627&idx=2&sn=e65f700bee531da5b16c6700ccf6a693&source=41#wechat_redirect>
,这里就不多啰嗦了,下面主要介绍PCA算法和LDA算法在MNIST数据集上的应用。
  主要参考的是Kaggle上的一篇Kernel,也可以直接去看这篇Kernel,这里附上链接:Interactive Intro to
Dimensionality Reduction

<https://www.kaggle.com/arthurtok/interactive-intro-to-dimensionality-reduction>

python代码:

导入一些基本的库
import numpy as np # linear algebra import pandas as pd # data processing, CSV
file I/O (e.g. pd.read_csv) import plotly.offline as py
py.init_notebook_mode(connected=True) import plotly.graph_objs as go import
plotly.toolsas tls import seaborn as sns import matplotlib.image as mpimg import
matplotlib.pyplotas plt import matplotlib # Import PCA from
sklearn.decompositionimport PCA
PCA


  简而言之,PCA是一种线性变换算法,它试图将我们数据的原始特征投射到更小的特征集合(或子空间)上,同时保留大部分信息。为了做到这一点,算法试图在新的子空间中找到最合适的方向/角度(即主成分),该主成分能最大化方差。为什么要最大化方差呢?请看本文的第一个链接。

MNIST数据集

  MNIST数据集是计算机视觉中的数字数据集,基本上算是机器学习中的入门级数据集了,可以到Kaggle上下载:MNIST Dataset
<https://www.kaggle.com/arthurtok/interactive-intro-to-dimensionality-reduction/data>

#载入数据集,查看维度 train = pd.read_csv('../input/train.csv') print(train.shape)
#(42000, 785) #将训练集的特征和标签分开 target = train['label'] train = train.drop("label"
,axis=1)# Drop the label feature
计算特征向量

  先将数据对每个特征进行标准化处理得到X_std,然后计算出协方差矩阵cov_mat,计算协方差矩阵的特征值eig_vals和特征向量 eig_vecs
。并把每个特征值与它对应的特征向量绑定起来作为一个特征对eig_pairs,按特征值的大小对特征对进行从大到小排序。
  之后计算特征值的和tot以及每个特征占特征值和的比例var_exp,特征值占特征值和的累计比例cum_var_exp
#将数据集进行标准化处理 from sklearn.preprocessing import StandardScaler X = train.values
X_std = StandardScaler().fit_transform(X) # 计算协方差矩阵的特征值和特征向量 mean_vec = np.mean
(X_std, axis=0) cov_mat = np.cov(X_std.T) eig_vals, eig_vecs = np.linalg.eig
(cov_mat)#创建(特征值,特征向量)元组对 的列表 # Create a list of (eigenvalue, eigenvector)
tuples eig_pairs = [ (np.abs(eig_vals[i]),eig_vecs[:,i]) for i in
range(len(eig_vals))]# Sort the eigenvalue, eigenvector pair from high to low
eig_pairs.sort(key = lambda x: x[0], reverse= True) # Calculation of Explained
Variance from the eigenvalues tot = sum(eig_vals) #特征值的和 var_exp = [(i/tot)*100
for iin sorted(eig_vals, reverse=True)] #单个特征值所占的比重 cum_var_exp = np.cumsum
(var_exp)# 特征值累计比重
画出特征值比例图以及特征值累计比例图

  具体代码可以参考原文,这里就不贴了。


  上图右上角的小图与大图是一样的,只是做了个缩放。黄色线和绿色线是特征值的累计比例,可以看出累计比例是100%的,没有问题。黑色线和红色线是单个特征值的比例。横坐标到784为止,代表784维特征。

  正如我们所看到的,在我们的784个特性或列中,大约90%的解释方差可以用200以上的特性来描述。因此,如果想在这上面实现一个PCA,提取前200个特征将是一个非常符合逻辑的选择,因为它们已经占了大约90%的信息。

可视化特征向量


  如上所述,由于PCA方法试图捕获最大方差的最优方向(特征向量)。因此,可视化这些方向及其相关特征值可能是有用的。为了快速实现,这里只会提取PCA特征值前30个(使用Sklearn的
.components_ 方法)特征向量。
# 调用 SKlearn的 PCA 方法 n_components = 30 pca =
PCA(n_components=n_components).fit(train.values) eigenvalues =
pca.components_.reshape(n_components,28, 28) #提取PCA主成分(特征值),仔细想想应该是特征向量
eigenvalues = pca.components_#画图 n_row = 4 n_col = 7 # Plot the first 8
eignenvalues plt.figure(figsize=(13,12)) for i in list(range(n_row * n_col)): #
for offset in [10, 30,0]: # plt.subplot(n_row, n_col, i + 1) offset =0
plt.subplot(n_row, n_col, i +1) plt.imshow(eigenvalues[i].reshape(28,28), cmap=
'jet') title_text = 'Eigenvalue ' + str(i + 1) plt.title(title_text, size=6.5)
plt.xticks(()) plt.yticks(()) plt.show()


  上面的小块描绘了PCA方法为我们的MNIST数据集生成的前30个最优方向或主成分轴。有趣的是,当把第一个分量“特征值1”与第28分量“特征值28”进行比较时,很明显,在寻找最大方差中生成了更复杂的方向或成分,从而使新特征子空间的方差最大化。

用Sklearn实现PCA算法

  现在使用Sklearn工具包,实现主成分分析算法如下:
# Delete our earlier created X object del X # 值采用前6000个样本来加速计算 X= train[:6000
].values del train # 标准化数据 X_std = StandardScaler().fit_transform(X) # Call the
PCAmethod with 5 components. pca = PCA(n_components=5) pca.fit(X_std) X_5d = pca
.transform(X_std) # "Target"也要取前6000个 Target = target[:6000]
  X_std为标准化后的数据,shape为(6000,784),X_5d为降维之后的数据,shape为(6000,5)

画前2个主成分的散点图


  当涉及到这些降维的方法时,散点图是最常用的,因为它们允许对聚类(如果有的话)进行大而方便的可视化,而这正是我们在绘制前2个主成分时所要做的事情。下面是以5个主成分中的第一个主成分和第二个主成分为横纵坐标画的散点图,代码可以看原文。

  正如从散点图中观察到的那样,你可以从颜色的集体斑点中分辨出一些明显的簇。这些簇群表示了不同的点潜在地代表了不同的数字。但是
,由于PCA算法是无监督算法,上面的图之所以有颜色,是因为画图时加上了数据集的标签,如果不加数据集的标签,是看不到这些颜色的。那么,如果没有加入颜色,我们如何能够将我们的数据点分离到新的特征空间中呢?

  首先,我们用Sklearn建立了KMeans聚类方法,并使用fit_predict方法计算集群中心,并预测第一个和第二个PCA投影的成分指标(看看是否可以观察到任何可感知的簇群)。KMeans聚类散点图:
from sklearn.cluster import KMeans # KMeans clustering # Set a KMeans
clustering with 9 components ( 9 chosen sneakily ;)as hopefully we get back our
9 class labels) kmeans = KMeans(n_clusters=9) # Computecluster centers and
predictcluster indices X_clustered = kmeans.fit_predict(X_5d)


  从视觉上看,KMeans算法生成的簇群似乎在簇群之间提供了更清晰的划分,相比之下,我们的PCA投影中添加了类标签。这并不奇怪,因为PCA是一种无监督的方法,因此它并不能优化分离类别。然而,分类的任务是由我们将要讨论的下一个方法完成的。

LDA


  LDA像PCA一样,也是一种线性变换方法,通常用于降维任务。但与非监督学习算法不同,LDA属于监督学习方法。由于LDA的目标是提供关于类标签的有用信息,LDA将通过计算成分坐标轴(线性鉴别器)来最大化不同类之间的距离。
  简而言之,二者区别是:LDA与PCA的对比,PCA选择样本点投影具有最大方差的方向,LDA选择分类性能最好的方向:
  Sklearn工具包也自带了内置LDA函数,因此我们调用LDA模型如下:
lda = LDA(n_components=5) # Taking in as second argument the Target as labels
X_LDA_2D = lda.fit_transform(X_std, Target.values )

  LDA实现的语法非常类似于PCA的语法。使用一次调用fit和transform方法,它将LDA模型与数据相拟合,然后通过应用LDA维度缩减来实现转换。然而,由于LDA是一种有监督的学习算法,所以对于用户必须提供的方法有第二个参数,这将是类标签,在本例中是数字的目标标签。

LDA可视化散点图



  从上面的散点图中,我们可以看到,在使用LDA时,与使用类标签实现PCA相比,数据点更清晰地聚集在一起。这是拥有类标签来监督学习的方法的内在优势。简而言之,为正确的工作选择合适的工具。