FingercrossAI
首发于FingercrossAI
降维技术解析:PCA, t-SNE and Auto Encoders

降维技术解析:PCA, t-SNE and Auto Encoders

降维技术对于统计学专业的同学来说并不陌生,特别是PCA和LDA,算是玩得比较溜的算法之一。 我们可能认为用PCA降低了输入数据的维度同时保有了主要信息,将是解决过拟合的有效方法,但由于PCA整个方案都不考虑我们结果的值y,因此在实际工作或者打比赛中,PCA并不被推荐用来避免过拟合,还是老老实实的用正则化吧。自编码器作为一种神经网络降维技术,近年来越来越流行,最近在看谷歌和uber发表的一些paper的时候,常常能看到自编码器技术的应用。因此借这个机会梳理一下三大维降维技术:PCA,t-SNE和自编码器。


PCA (Principal Component Analysis,主成分分析)

PCA通过正交变换将一组可能存在相关性的变量转换为一组线性不相关的变量,即把多指标转化为少数几个综合指标,转换后的这组变量就叫做主成分,其中每个主成分都能够反映原始变量的大部分信息,且所含信息互不重复,以此达到降维的目的。

1.算法步骤

设有 mn 维数据。

  1. 将原始数据按列组成 n m 列矩阵 X
  2. X 的每一行(代表一个属性字段)进行零均值化,即减去这一行的均值;
  3. 求出协方差矩阵 C=\frac{1}{m}XX^{T}
  4. 求出协方差矩阵的特征值及对应的特征向量;
  5. 将特征向量按对应特征值大小从上到下按行排列成矩阵,取前 k 行组成矩阵 P
  6. Y=PX 即为降维到k维后的数据。

2.数学原理

PCA中有两个很重要的思想:

  • 最大可分性思想,即样本点在超平面上的投影能尽可能的分开。基于最大可分性思想,我们要找的方向是使得降维后损失最小的方向,可以理解为投影后的数据尽可能的分开,这种分散程度可以用数学上的方差来表示,方差越大数据越分散。
  • 主成分相互独立思想,即主成分之间不能存在线性相关性的,不然的话必然存在重复表示的信息,那么第二个主成分只能在与第一个主成分正交的方向上选择。

协方差矩阵就代表了字段与字段之间的相关关系,因此我们的目标就是协方差矩阵对角化,并且在对角线上将元素按大小从上到下排列。这个协方差矩阵是对称的,我们知道,实对称矩阵是一定能对角化的。

我们进一步看下原协方差矩阵与基变换后的对角阵之间的关系:设原始数据矩阵X对应的协方差矩阵为C,而P是一组基按行组成的矩阵,设Y=PX,则YXP做基变换后的数据。设Y的协方差矩阵(对角阵)为D,我们推导一下DC的关系:

\begin{align} D &= \frac{1}{m}YY^\top \\ &=\frac{1}{m}(PX)(PX)^\top\\ &= \frac{1}{m}PX X^\top P^\top\\ &= P(\frac{1}{m}X X^\top) P^\top\\ &=PCP^\top\end{align}\\

其中,P的每一行都是C的一个特征向量。

降维投影可视化效果

t-SNE

t-SNE算法仿射(affinitie)变换将数据点映射到概率分布上,利用条件概率来衡量数据点之间的相似性,通过使数据集在高维和低维两个空间的条件概率尽可能接近,将数据从高维空间映射到低维空间。通过t-SNE降维不仅可以保持数据的差异性,而且可以很好地保持数据的局部结构。

1.算法步骤

t-SNE算法步骤如下图所示。

t-SNE算法步骤

2.数学原理

下面就写一下自己在阅读时对于这个流程中每一步的理解,序号对应图中的序号。

(0)算法的输入有两个:

  1. n m 维数据;
  2. Perp ,困惑度。困惑度可以解释为一个点附近的有效近邻点个数,SNE对困惑度的调整比较有鲁棒性,通常选择5-50之间。

(1)是SNE算法中设置的一个条件概率用来衡量高维数据的相似性, p_{j|i} 衡量的是数据点j作为数据点 i 的邻域的概率; σ 是方差,这个方差大小与输入的困惑度有关。

(2)是为了解决引入异常值的问题,比如x_i是异常值,那么||x_i−x_j||^{2}会很大,对应的所有的 jp_{ij}都会很小,导致低维映射下的 y_i 对损失函数影响很小。为了解决这个问题,将联合概率分布定义修正为:  p_{ij}=\frac{p_{i∣j}+p_{j∣i}}{2} , 使得每个点对于损失函数都会有一定的贡献。

(3)—(4)不太理解为什么 Yn*n 维的,按道理说 Y 是最终的输出,维度应该是 n*n\_components

(5)是SNE算法中设置的一个条件概率用来衡量低维数据的相似性。

(6) Q_{n,n} 表示低维数据集中所有其他数据点之间的相对条件概率。

(7)是目标函数(cost function),是两个分布之间的距离-KL散度(Kullback-Leibler divergences)。

(4)(5)(6)(7)是个循环,通过不断地利用梯度下降算法,得到最优解。


Auto Encoders(自编码器)

自编码器是一种用于高效编码的无监督学习人工神经网络,其目标是通过使用比输入节点更少的隐藏节点(在编码器一端)预测输入(训练该网络使其输出尽可能与输入相似),为此该网络需要尽可能多地将信息编码到隐藏节点中。

在结构上,自编码器的最简单形式是一个前馈非递归神经网络,它与多层感知器(MLP)非常相似,具有输入层、输出层以及连接它们的一个或多个隐藏层。然而自编码器和MLP之间的差异在于,在自编码器中,输出层具有与输入层相同数量的节点,并且不是训练预测给定的目标值,而是将它们自己作为目标值投入训练。因此自编码器属于无监督学习模型。

自编码器总是由两个部分组成,编码器和解码器。在最简单的情况下,一个自编码器只有一个隐藏层,该隐藏层接收输入并将其映射到输出上(如下图所示)。自编码器也是被训练以最小化损失函数(例如MSE):

如上所述,自编码器主要致力于减少特征空间,以提取数据的基本特征,而传统的深度学习则扩大了特征空间,捕捉数据中的非线性和微妙的相互作用。自编码器也可以看作PCA的非线性替代。

具有单个隐藏层的自编码器示意结构

代码实现

引用莫烦大神的代码来看一下如何实现一个Autoencoder。

"""
To know more or get code samples, please visit my website:
https://morvanzhou.github.io/tutorials/
Or search: 莫烦Python
Thank you for supporting!
"""

# please note, all tutorial code are running under python3.5.
# If you use the version like python2.7, please modify the code accordingly

# 9 - Autoencoder example

# to try tensorflow, un-comment following two lines
# import os
# os.environ['KERAS_BACKEND']='tensorflow'
import numpy as np
np.random.seed(1337)  # for reproducibility

from keras.datasets import mnist
from keras.models import Model
from keras.layers import Dense, Input
import matplotlib.pyplot as plt

# download the mnist to the path '~/.keras/datasets/' if it is the first time to be called
# X shape (60,000 28x28), y shape (10,000, )
(x_train, _), (x_test, y_test) = mnist.load_data()

# data pre-processing
x_train = x_train.astype('float32') / 255. - 0.5       # minmax_normalized
x_test = x_test.astype('float32') / 255. - 0.5         # minmax_normalized
x_train = x_train.reshape((x_train.shape[0], -1))
x_test = x_test.reshape((x_test.shape[0], -1))
print(x_train.shape)
print(x_test.shape)

# in order to plot in a 2D figure
encoding_dim = 2

# this is our input placeholder
input_img = Input(shape=(784,))

# encoder layers
encoded = Dense(128, activation='relu')(input_img)
encoded = Dense(64, activation='relu')(encoded)
encoded = Dense(10, activation='relu')(encoded)
encoder_output = Dense(encoding_dim)(encoded)

# decoder layers
decoded = Dense(10, activation='relu')(encoder_output)
decoded = Dense(64, activation='relu')(decoded)
decoded = Dense(128, activation='relu')(decoded)
decoded = Dense(784, activation='tanh')(decoded)

# construct the autoencoder model
autoencoder = Model(input=input_img, output=decoded)

# construct the encoder model for plotting
encoder = Model(input=input_img, output=encoder_output)

# compile autoencoder
autoencoder.compile(optimizer='adam', loss='mse')

# training
autoencoder.fit(x_train, x_train,
                epochs=20,
                batch_size=256,
                shuffle=True)

# plotting
encoded_imgs = encoder.predict(x_test)
plt.scatter(encoded_imgs[:, 0], encoded_imgs[:, 1], c=y_test)
plt.colorbar()
plt.show()

参考资料

PCA 的数学原理和可视化效果www.jianshu.com图标机器之心:基于TensorFlow理解三大降维技术:PCA、t-SNE 和自编码器zhuanlan.zhihu.com图标t-SNE完整笔记www.datakit.cn图标机器学习: t-Stochastic Neighbor Embedding 降维算法 (一)blog.csdn.net
机器学习: t-Stochastic Neighbor Embedding 降维算法 (二)blog.csdn.net图标Anomaly Detection in Time Series using Auto Encodersphilipperemy.github.io图标


推荐阅读:

徐小贱民:FingercrossAI链接汇总zhuanlan.zhihu.com图标

编辑于 2018-02-23

文章被以下专栏收录