在机器学习和统计学领域,降维是指在某些限定条件下,降低随机变量个数,得到一组“不相关”主变量的过程。对数据进行降维一方面可以节省计算机的储存空间,另一方面可以剔除数据中的噪声并提高机器学习算法的性能。(实际上通过降维还可以实现数据可视化,但是前提是将原始数据降到2D或者3D才可以)。
数据降维的根本:降低数据维度、降维后的数据能尽可能的代表原始数据。
数据降维和特征选择是存在差异的,二者最终的目的都是想减少特征的维度,但是二者的实现方式上有本质的区别。数据降维是将原始数据映射到低维子空间,以达到降低维数的目的,但是这个过程中数据的特征发生了本质的变化,新的子空间的特征再是原来的特征,所以通常不容易赋予经过降维后的数据新特征的物理意义。特征选择是在原来的n个特征中选取其中的s个(s<= n),选取的s个特征是原来特征空间的子集,它还是有着和原来特征一样的物理意义。这也实现了降低特征维数的目的。
降维技术有很多种,这篇文章介绍常见的5种数据降维技术:主成分分析(Principal Component Analysis,PCA)、因子分析(Factor Analysis)、独立成分分析(Independent Component Analysis,ICA)、奇异值分解(singular value decomposition,SVD)、线性判别分析(linear discriminant analysis,LDA)。
目录
1. 主成分分析(PCA)
PCA是一种常用的降维技术,既然是降维,我们当然希望能够把特征矩阵通过某种方式使得新的特征矩阵的维度降低。实际上下面先简要说明一下PCA的原理和实现步骤。 PCA 的原理:通过正交变换将一组可能存在相关性的变量转换为一组线性不相关的变量,转换后的这组变量叫主成分。主成分是原特征的线性组合。(前提是变换后的矩阵需要保留变换前矩阵的主要信息,不然降维没有意义)
既然要进行正交变换,那么我们就得需要一组正交基向量,求解这组正交基向量就成了主成分分析的关键。
PCA的步骤:
1. 对特征矩阵进行中心化,即对矩阵按列求均值得到行向量,然后用特征矩阵减去行向量(由于python的广播机制,行向量扩充为和特征矩阵同等维度的矩阵)得到矩阵X
2. 求矩阵X的协方差矩阵,并对协方差矩阵进行特征分解,得到特征值和其对应的特征向量
3. 对特征值按照从大到小的顺序排序,假设取前k 个特征值,然后取这k 个特征值对应的特征向量作为一组基向量
4. 用矩阵X 和基向量相乘,就可以把矩阵X 变换到维度更低的子空间,得到新的矩阵Y ,它就是降维后的矩阵。
PCA 的原理和步骤都很简单,其程序实现也很简单。但是PCA中还是有几个需要注意的点。为什么要先进行中心化?为什么要选择协方差矩阵,直接对中心化后的矩阵进行特征分解不可以吗?为什么要对协方差矩阵进行特征分解,特征分解的意义何在,特征分解后得到的特征值和特征向量又有什么用?接下来,逐一进行分析。
1.1 对矩阵进行中心化
为什么要对数据矩阵进行中心化,直接对数据矩阵进行处理不可以吗。首先我们先说下什么是中心化,中心化又称为零均值化,中心化就是指变量减去均值。中心化后的数据的均值为0。比如有5个数据(1,9,2,4,5),首先这5个数的均值为4.2,将其中心化后得到的数据为(-3.2,4.8,-2.2,-0.2,0.8),可以看出,中心化后的数据的均值为0。那么这有什么用呢,中心化可以把样本点移动到原点附近。以上面的5个数为例,其在中心化前后的图分别如下:
可以看到,通过中心化后,数据点移动到了原点附近。在二维空间中,中心化前后的对比图如下:
数据点的中心移动到了(0,0)。通过中心化,能够更好的描述主成分的方向。
1.2 协方差矩阵
通过上面的中心化后我们得到了新的矩阵X,像上面所疑惑的,我们为什么不直接对中心化后的矩阵X进行操作而是选择其协方差矩阵进行操作。我们知道,PCA的作用主要有两种:数据压缩(即去除冗余)、去噪声(提高算法性能)。那么这两种作用跟协方差矩阵又有什么关系呢。
首先对于数据压缩来说,我们希望特征间的相关性尽可能低,相关性低能代表什么呢,这能代表信息的冗余低,留下的数据都是包含主要信息的数据。比如在某个数据集中,我有3个特征都是表示某物体的长度,但是这3个特征表示的长度的单位不同,分别是cm、m、inches。显然这三个特征见得相关性很高,因为对于长度来说,我们完全可以用一种单位长度来表示假设用cm来衡量物体的长度,那么以m和inches来衡量物体长度的那两个特征就是冗余信息,那我们可不可以直接把冗余的特征去掉呢?嗯。。。。,实际上应该是可以的,但是PCA并不是这样做的,这也是降维和特征选择的主要区别,PCA是对旧特征通过线性变换而得到一些新的特征,而新特征能很好的描述某一物体,且通常情况下新特征的数量要比旧特征的数量少。那么特征间的相关性我们应该如何衡量呢,可以通过协方差来衡量特征间的相关性。协方差越小,特征间的相关性越小。而我们同时还希望留下来的特征,此处是以cm为衡量长度的特征的方差尽量大,我们都知道,数据的最大方差代表数据的最重要的信息,所以特征本身的方差也是我们需要关注的。那么有没有什么数据结构既能存储特征间的协方差又能存储各特征本身的方差呢,协方差矩阵。
那么同样的,对于去噪声来说,我们希望我们需要的信号的能量要尽可能大,这样它包含的信息量才大,所以我们需要信号的方差要大;同时为了避免干扰,我们希望信号和噪声之间的相关性要低,如果信号和噪声的相关性高的话,我们就分不清哪个是信号,哪个是噪声了,这里的相关性同样需要用协方差来描述。那么同时存储协方差和方差的数据结构我们同样需要协方差矩阵的登场。现在一切都变的明朗了,这就是为什么要研究特征矩阵的协防差矩阵的原因。
那么什么是协方差矩阵呢,协方差矩阵又称:离差矩阵、方差-协方差矩阵。假设有3个样本a、b、c按行组成维度为3*n的矩阵X,如下:
那么矩阵X对应的协方差矩阵为:
可以看到,协方差矩阵是一个对称矩阵,而且对角线上的元素为方差;非对角线上的元素为协方差。这样一个矩阵完美的包含了方差和协方差。
1.3 特征分解
得到了特征矩阵X的协方差矩阵后,为什么要对它进行特征分解呢,特征分解后得到的特征值和特征向量又有什么用呢。在上一小节提到过,我们希望特征间的相关性越小越好,而希望特征本身的能量越大越好,这对应到协方差矩阵中就是,我们希望协方差矩阵的非对角线的元素越小越好甚至为0更好,而希望对角线上的元素越大越好,但是并不希望对角线上的每个元素的值都很大,这样的话我们就不能降低特征矩阵的维度了,理想的情况是,对角线上有些元素的值比较大,比如k(k<<n)个元素的值占到所有元素值总和的90%或更多,这样我们就可以只取这k个元素对应的特征就能够代表原特征矩阵的大部分信息了。
说了这么多,说出了我们的期望的协方差矩阵的样子,但是实际获得的协方差矩阵并不能满足:非对角线上的元素为0,对角线上k个元素的值的和占到所有元素值的和的90%或者更多。这时候,特征分解就出现了,特征分解可以找到一个矩阵,这个矩阵可以协方差矩阵相似,且可以满足我们期望的矩阵的样子,这个操作就是把协方差矩阵对角化。把一个矩阵进行对角化这是本科线性代数中就学过的知识。但是并不是所有的矩阵都可以相似对角化的,因为协方差矩阵是是对称矩阵,所以它一定可以相似对角化。协方差矩阵可以用下面的式子表示:
其中是一个对角矩阵,且对角线上的元素是协方差矩阵的特征值。而P就是由特征值对应的特征向量组成的矩阵。这时,我们可以把对角线上的值按照从小到大的顺序排序,取前k个特征值,其对应的k个特征向量就可以作为一组基向量,把中心化后的特征矩阵从高维空间通过线性变换映射到低维空间。
1.4 PCA的实现
上面就是PCA的一个简单的程序实现。我们使用sklearn.decomposition中的函数PCA,有关它的参数如下图:
关于参数的详细说明可以自行参考PCA的函数说明。在这里我只说明一点,就是参数random_state的使用,它默认是None,它也可以接收一个int数。random_state实际上就相当于随机种子,即random.seed()。那么这个东西它有什么作用呢,接下来先通过实际的程序来观察一下:
当不设置种子点的时候,每次随机生成20-78之间的整数的时,得到的10个数都是不同的。接下来,我们设置一个随机种子点如下:
我们设置了种子点random.seed(1),两次随机生成的整数是一样的。需要注意的是,种子点是设置在了test()方法中,所以在if __name__ == '__main__':中创建的两个test()对象得到的内容是一样的,无论运行多少次,得到的都是这10个数;如果把种子点设置在test()方法的外边,那么if __name__ == '__main__':中的两个test()对象得到的随机数是不同的,但是每个单独的test()在多次运行中生成的随机数都是一样的。比如第一个test()生成的随机数为(22,34,56,76,45,67,48,57,77,49),第二个test()生成的随机数为(22,23,24,25,26,34,56,48,69,71),那么无论运行多少次程序,第一个test()生成随机数都是(22,34,56,76,45,67,48,57,77,49);第2个test()生成的随机数都是(22,23,24,25,26,34,56,48,69,71)。
接下来随便我们换一个种子点:random.seed(13),如下所示:
无论运行多少次,得到的序列都是不变的。我们可以发现,种子点设置的不同,最后生成的序列也是不同的,但是一旦种子点固定下来,生成的序列就是一成不变的。random_state和random.seed()的作用是一样的。
那么为什么要设置random_state这个参数呢,这是为了让不同的人在运行这个程序时得到相同的结果,而且这个参数一般只会只存在于有随机性的方法中,比如train_test_split、SVC等。还需注意的一点是,一般在调参的时候,我们不要改变random_state的值。
上面的说的都是线性降维,对于非线性降维,可以使用sklearn.decomposition的kernel-PCA来实现。
以上就是关于PCA的主要内容,如果想了解更多关于PCA的内容,可以查看参考文献中的文章。
2. 线性判别分析(LDA)
在机器学习领域,LDA对应着两种不同的模型,其中一个模型就是这一小节要讲的,Linear Discriminant Analysis(线性判别分析),主要用于分类和降维;而另一个模型为 ,Latent Dirichlet Allocation(潜在狄利克雷分布),其在主题模型中有非常重要的地位,主要用于文本分类。
LDA的思想很简单:把样本点投影到一条直线上,使得同类样本的投影点尽可能接近、异类样本的投影点尽可能远离。如下图所示(图片来自周志华老师的《机器学习》):
而我们需要的就是寻找这样的直线或超平面,对于同样的样本点,投影到不同的直线会得到完全不同的投影点。如下图所示:
显然,我们更愿意得到右边的投影直线,因为它满足了我们的需求:类内样本点距离近而类间样本点有明显的界限。通过这样一条直线,我们把原本在二维空间的样本点投影到了一维空间,实现了降维。同时,实现了分类。
这是直观上的需求,那么我们应该通过什么来度量或者怎么通过数学来得出这样一条直线或超平面呢。接下来以二分类为例,对LDA的原理进行说明。
2.1 LDA原理
给定数据集。令表示第i示例的集合,有个样本,其中。如果将两类样本的样本点投影到直线y上,那么。在x的特征空间上定义均值向量为:,那么在特征空间y上的均值向量为:
我们说过,将样本点投影到直线上时想让同一类别的样本点尽可能距离近,而不同类别的样本点尽可能远离。那么我们可以用特征空间y上两种类别的均值向量的距离来表示类间距离,即,我们希望让尽可能大。
那么同类投影点的尽可能近该怎么表示呢。在x特征空间上定义协方差,那么在特征空间y上的均值向量为:
要想使同类样本点的投影点尽可能接近,那么只需让同类样本点的投影点的协方差尽可能小,即尽可能小。综合考虑类内间距和类间间距两种因素,我们可以得出目标函数:
定义为类内散度矩阵(within-class scatter matrix):
定义为类间散度矩阵(between-class scatter matrix):
那么目标函数可重写为:
我们的目的是使目标函数的分母(类内间距)尽可能小,而目标函数的分子(类间间距)尽可能大。那么我们需要最大化目标函数。
对于最大化目标函数我们有两种方式,其中一种是对求导数,并令求得w的值。具体求解过程如下:
另一种求解方法是西瓜书中的求解,即令,那么求解 的最大值就变成了有约束条件问题:
由拉格朗日乘子法得到拉格朗日函数:
对求偏导并令其等于0有:
最后得到:
注意到, ,对这个式子两边同时乘以得 ,因为y的特征空间为以为空间,所以是标量,不妨令为,那么可写为:
将其带入可解出为:
3. 独立成分分析(ICA)
有关独立成分分析的原理,请参考这篇文章。ICA的使用,建议参考sklearn中的文档。
4. 奇异值分解(SVD)
有关奇异值分解的内容,请参考这篇文章
参考文献
1. 如何通俗易懂地讲解什么是 PCA 主成分分析? https://www.zhihu.com/question/41120789/answer/474222214
2. PCA的数学原理(转) https://zhuanlan.zhihu.com/p/21580949
3. 中心化(又叫零均值化)和标准化(又叫归一化) https://blog.csdn.net/GoodShot/article/details/80373372
4. 如何理解矩阵特征值和特征向量? https://www.matongxue.com/madocs/228.html.
5. 机器学习实战
6. 《机器学习》---3.4 线性判别分析 周志华
7. 史上最好的LDA(线性判别分析)教程 https://blog.csdn.net/jnulzl/article/details/49894041