前言

Github:本文代码放在该项目中:NLP相关Paper笔记和代码复现
说明:讲解时会对相关文章资料进行思想、结构、优缺点,内容进行提炼和记录,相关引用会标明出处,引用之处如有侵权,烦请告知删除。
转载请注明:DengBoCong

白化是一种线性变换,用于对源信号进行去相关,是一种重要的预处理过程,其目的就是降低输入数据的冗余性,使得经过白化处理的输入数据具有如下性质:

  • 特征之间相关性较低
  • 所有特征具有相同的方差。

其中,PCA白化保证了所有特征分布均值为0,方差为1,而ZCA白化则保证了所有特征分布均值为0,方差相同。PCA白化可以用于降维也可以去相关性,而ZCA白化主要用于去相关性,且尽量使白化后的数据接近原始输入数据。

白化是机器学习里面常用的一种规范化数据分布的方法,特别是用来在机器学习模型中用来解决Covariate Shift问题(Covariate Shift是啥可以看这篇文章:论文阅读笔记:Covariate Shift: 基于机器学习分类器的回顾和分析

在深度学习中,Covariate Shift问题也存在,不过叫做另一个名字Internal Covariate Shift,同样在深度学习中解决Internal Covariate Shift问题的办法有很多,比如我们熟悉的Batch Normalization、Layer Normalization等等归一化方法,感兴趣的小伙伴可以参考这篇文章:深度学习中眼花缭乱的Normalization学习总结

这篇文章就来对PCA (主成分分析)、ZCA (零相成分分析)和ICA(独立成分分析)进行回顾和总结。本文涉及到的代码已放置在GitHub:Experiment

写在前面

在我们接下来进行下面讲解之前,我们先来了解几个概念理解结论:

  • 如果假设 B 的模为 1,则A 与 B 的内积值等于 A 向 B 所在直线投影的标量大小,这就是内积的一种几何解释,即让$|B|=1$,那么$A\cdot B=|A||B|cos(\alpha)=|A|cos(\alpha)$。注意投影是一个标量,所以可以为负。
  • 要准确描述向量,首先要确定一组基,然后给出在基所在的各个直线上的投影值,就可以了。为了方便求坐标,我们希望这组基向量模长为 1。因为向量的内积运算,当模长为 1 时,内积可以直接表示投影。然后还需要这组基是线性无关的,我们一般用正交基,非正交的基也是可以的,不过正交基有较好的性质。
  • 矩阵相乘找到了一种物理解释:两个矩阵相乘的意义是将右边矩阵中的每一列向量 [公式] 变换到左边矩阵中以每一行行向量为基所表示的空间中去。也就是说一个矩阵可以表示一种线性变换,如下矩阵乘法。
    $$\begin{bmatrix}p_1\p_2\…\p_R\end{bmatrix}(a_1\ a_2\ …\ a_M)=\begin{bmatrix}p_1a_1 & p_1a_2 & … & p_1a_M\ p_2a_1 & p_2a_2 & … & p_2a_M\ … & … & … & …\ p_Ra_1 & p_Ra_2 & … & p_Ra_M\end{bmatrix}$$
    其中 $p_i$ 是一个行向量,表示第 $i$ 个基, $a_j$ 是一个列向量,表示第 $j$ 个原始数据记录,实际上也就是做了一个向量矩阵化的操作。
  • 我们应该如何选择 K 个基才能最大程度保留原有的信息?问题可以形式化表述为:寻找一个一维基,使得所有数据变换为这个基上的坐标表示后,方差值最大。
  • 降维问题的优化目标:将一组 N 维向量降为 K 维,其目标是选择 K 个单位正交基,使得原始数据变换到这组基上后,各变量两两间协方差为 0,而变量方差则尽可能大(在正交的约束下,取最大的 K 个方差)

降维

首先理解降维,降维就意味着信息的丢失,不过鉴于实际数据本身常常存在的相关性,我们可以想办法在降维的同时将信息的损失尽量降低。例如上面淘宝店铺的数据,从经验我们可以知道,“浏览量”和“访客数”往往具有较强的相关关系,而“下单数”和“成交数”也具有较强的相关关系。这里我们非正式的使用“相关关系”这个词,可以直观理解为“当某一天这个店铺的浏览量较高(或较低)时,我们应该很大程度上认为这天的访客数也较高(或较低)”。

上面给出的是降维的朴素思想描述,可以有助于直观理解降维的动机和可行性,但并不具有操作指导意义。例如,我们到底删除哪一列损失的信息才最小?亦或根本不是单纯删除几列,而是通过某些变换将原始数据变为更少的列但又使得丢失的信息最小?到底如何度量丢失信息的多少?如何根据原始数据决定具体的降维操作步骤?要回答上面的问题,就要对降维问题进行数学化和形式化的讨论。也就是我们接下来要讨论的PCA和ZCA,不过在此之前,我还想举一个更加生动的例子。下图的平面直角坐标系中有五条数据:
在这里插入图片描述
现在问题来了:如果我们必须使用一维来表示这些数据,又希望尽量保留原始的信息,你要如何选择?这个问题实际上是要在二维平面中选择一个方向,将所有数据都投影到这个方向所在直线上,用投影值表示原始记录。这是一个实际的二维降到一维的问题。那么如何选择这个方向(或者说基)才能尽量保留最多的原始信息呢?一种直观的看法是:希望投影后的投影值尽可能分散,因为如果重叠就会有样本消失。当然这个也可以从熵的角度进行理解,熵越大所含信息越多,用数学来衡量就是使用方差和协方差。

LDA

LDA的全称是Linear Discriminant Analysis(线性判别分析),是一种supervised learning。有些资料上也称为是Fisher’s Linear Discriminant,因为它被Ronald Fisher发明自1936年,Discriminant这次词我个人的理解是,一个模型,不需要去通过概率的方法来训练、预测数据,比如说各种贝叶斯方法,就需要获取数据的先验、后验概率等等。

LDA的原理是,将带上标签的数据(点),通过投影的方法,投影到维度更低的空间中,使得投影后的点,会形成按类别区分,一簇一簇的情况,相同类别的点,将会在投影后的空间中更接近。即给出一个标注了类别的数据集,投影到了一条直线之后,能够使得点尽量的按类别区分开,比如在二分类问题中,如下图所示:
在这里插入图片描述

PCA

PCA(Principal Component Analysis) 是一种常见的数据分析方式,通过线性变换将原始数据变换为一组各维度线性无关的表示,可用于提取数据的主要特征分量,常用于高维数据的降维。LDA的输入数据是带标签的,而PCA的输入数据是不带标签的,所以PCA是一种unsupervised learning。

关于PCA的讲解,直接看这一篇文章就好了(PCA的数学原理),里面从基开始讲解,把每个点讲的通俗易懂,很值得阅读。我这里就单纯的陈列总结一下PCA的算法步骤:

设有m条n维数据。

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

PCA本质上是将方差最大的方向作为主要特征,并且在各个正交方向上将数据“离相关”,也就是让它们在不同正交方向上没有相关性。

因此,PCA也存在一些限制,例如它可以很好的解除线性相关,但是对于高阶相关性就没有办法了,对于存在高阶相关性的数据,可以考虑Kernel PCA,通过Kernel函数将非线性相关转为线性相关,关于这点就不展开讨论了。另外,PCA假设数据各主特征是分布在正交方向上,如果在非正交方向上存在几个方差较大的方向,PCA的效果就大打折扣了。

最后需要说明的是,PCA是一种无参数技术,也就是说面对同样的数据,如果不考虑清洗,谁来做结果都一样,没有主观参数的介入,所以PCA便于通用实现,但是本身无法个性化的优化。

ZCA

白化的目的是去相关和方差归一化,那么在上述PCA-Whtening中,只要达到这两个目的即可,计算方法并不唯一。换句话说,如果我们换一种方差归一化方法也是可以实现白化的,这就是下面要介绍的ZCA-Whitening。

如果 $R$ 是任意正交矩阵(any orthogonal matrix),即满足 $RR^T = R^TR = I$ (说它正交不太严格, $R$ 可以是旋转或反射矩阵),那么 $R$ 乘以 $x_{PCAwhite}$ 仍然具有单位协方差。在ZCA-Whitening中,令$R=U$(其中 U 是PCA白化中使用的特征向量矩阵) 。则我们定义ZCA白化的结果为:
$$x_{ZCAwhite}=Ux_{PCAwhite}$$

此时,数据的协方差矩阵依然是单位矩阵。

ICA

ICA又称盲源分离(Blind source separation, BSS),它假设观察到的随机信号 $x$ 服从模型 $x=As$,其中 $s$ 为未知源信号,其分量相互独立,$A$ 为一未知混合矩阵。ICA的目的是通过且仅通过观察 $x$ 来估计混合矩阵 $A$ 以及源信号 $s$。

大多数ICA的算法需要进行“数据预处理”(data preprocessing):先用PCA得到 $y$,再把 $y$ 的各个分量标准化(即让各分量除以自身的标准差)得到 $z$。预处理后得到的 $z$ 满足下面性质:

  • $z$ 的各个分量不相关
  • $z$ 的各个分量的方差都为1。

有许多不同的ICA算法可以通过 $z$ 把 $A$ 和 $s$ 估计出来。以著名的FastICA算法为例,该算法寻找方向使得随机变量 $w^Tz$ 的某种“非高斯性”(non-Gaussianity)的度量最大化。一种常用的非高斯性的度量是四阶矩 $E[(w^Tx)^4]$。类似PCA的流程,我们首先找 $w_1$ 使得 $E[(w^Tx)^4]$ 最大;然后在 $w_1$ 与正交的空间里找 $w_2$,使得 $E[(w^Tx)^4]$ 最大,以此类推直到找到所有的 $w_1,…,w_n$。可以证明,用这种方法得到的 $w_1^Tz,…,w_n^T$ 是相互独立的。

ICA认为一个信号可以被分解成若干个统计独立的分量的线性组合,而后者携带更多的信息。我们可以证明,只要源信号非高斯,那么这种分解是唯一的。若源信号为高斯的话,那么显然可能有无穷多这样的分解。

总的来说,ICA认为观测信号是若干个统计独立的分量的线性组合,ICA要做的是一个解混过程。而PCA是一个信息提取的过程,将原始数据降维,现已成为ICA将数据标准化的预处理步骤。

正则化

实践中需要实现PCA白化或ZCA白化时,有时一些特征值在数值上接近于0,这样在缩放步骤时我们除以 $\sqrt{\lambda_i}$ 将导致除以一个接近0的值;这可能使数据上溢 (赋为大数值)或造成数值不稳定。因而在实践中,我们使用少量的正则化实现这个缩放过程,即在取平方根和倒数之前给特征值加上一个很小的常数:

PCA白化和ZCA白化可视化

为了说明PCA和ZCA白化之间的区别,我们创建一些玩具数据。 具体来说,我们生成了两个相关时间序列 $x_1$ 和 $x_2$ 的1000个样本。

1
2
3
4
5
6
7
8
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(1)
mu = [0, 0]
sigma = [[5, 4], [4, 5]] # must be positive semi-definite
n = 1000
x = np.random.multivariate_normal(mu, sigma, size=n).T

这两个时间序列存储在shape为(2,1000)的NumPy数组 $x$ 中,同时,为了便于稍后可视化,这里固定20个最极端的值,并将它们的索引表示为set1(其余数据点的索引存储在set2中):

1
2
set1 = np.argsort(np.linalg.norm(x, axis=0))[-20:]
set2 = list(set(range(n)) - set(set1))

在这里插入图片描述
显然,这两个时间序列看起来高度相关,散点图的椭圆形表明,随着 $x_1$ 的值增加,$x_2$ 的值也趋于增加,实际上, $x_1$ 和 $x_2$ 之间的皮尔逊相关系数为0.80,可以通过以下公式计算:

1
2
print(np.corrcoef(x)[0, 1])
# 0.8020186259500502

PCA和ZCA均基于(经验)协方差矩阵的特征向量和特征值,特别地,协方差矩阵可以分解为其特征向量 $U$ 和特征值 $\Lambda$,例如($\Sigma$是协方差矩阵):
$$\Sigma = U\Lambda U^T$$
我们来计算玩具数据的这些值:

1
2
3
sigma = np.cov(x)
print(sigma)
evals, evecs = np.linalg.eigh(sigma)

请注意,在这里使用从数据得出的经验协方差矩阵,而不是普遍未知的真实协方差矩阵,此外,请注意,由于协方差矩阵始终是对称的,因此在这里使用优化的np.linalg.eigh函数,而不是更通用的np.linalg.eig版本(这也确保了我们总是得到真实的特征值而不是复杂的特征值)。当然,我们也可以直接在数据 $x$ 上使用np.linalg.svd(而不是协方差矩阵)来计算特征向量和特征值,在某些情况下,它们在数值上可能更稳定。

PCA白化

现在,我们的PCA白化矩阵 $W^{PCA}$ 可以写为:$W^{PCA}=\Lambda^{-\frac{1}{2}}U^T$,这也就意味着数据可以转换为:$z=W^{PCA}x=\Lambda^{-\frac{1}{2}}U^Tx$,因此,我们可以相应的白化我们的数据,代码实现如下:

1
z = np.diag(evals**(-1/2)) @ evecs.T @ x

现在我们可以来看看白化之后的数据是啥样:

在这里插入图片描述
我们可以很明显的看到该变换消除了两个时间序列之间的相关性,因为散点图现在看起来像一个球体(二维圆),因此PCA的另一个名称叫做sphering。np.corrcoef(z)[0,1]产生的值实际上等于零,从数据分布图我们可以看到,PCA旋转了所有数据点,如红点的新位置所示,它们不再位于大约45度的对角线上,而是现在与垂直轴对齐。

ZCA白化

同样的,ZCA的白化矩阵 $W^{ZCA}$ 可以表示为:$W^{ZCA}=U\Lambda^{-\frac{1}{2}}U^T$,ZCA白化类似于PCA白化,但不同点在于,$U$ 会进行额外的旋转。原始数据可以按如下方式转换:$z=W^{ZCA}x=U\Lambda^{-\frac{1}{2}}U^Tx$。接着,我们使用代码,将使用ZCA算法将白化数据并生成数据散点图:

1
z = evecs @ np.diag(evals**(-1/2)) @ evecs.T @ x

在这里插入图片描述
同样,由于散点图看起来是球形的,因此ZCA已将数据解相关(且np.corrcoef(z)[0,1]产生的值实际上等于零),与PCA相比,ZCA保留了原始数据点的方向,此属性为其命名为 “zero-phase”,因为它最小化了数据的原始相位(即方向)。

通过上面的实验,PCA和ZCA执行不同的旋转,所以如果目标是压缩原始数据,则使用PCA更好,而如果目标是使转换后尽可能与原始数据相似,则使用ZCA更好,因此ZCA无法用于压缩数据。值得一提的是,有时在白化之前对数据进行标准化可能会很有用,特别是如果各个源信号的比例不同。

参考资料