一、需求背景
针对我们关注的研究对象,我们通常会观察一系列特征属性,来对我们感兴趣的对象进行分析,因此我们会去收集大量有关的特征属性,属性越多,越有利于我们细致观测以及分析。但是随着属性增多,也会增加后续数据处理的运算量,带来较大的处理负担。例如,我们对一个城市或者一个区域进行研究的时候,会产生几十,甚至上百个数据也不奇怪。我们收集的数据越多,越有利于我们进行更加细致的研究和考察。但是,数据维度过大,无疑会使得问题分析变得复杂。同时,有一个现象,就是样本的特征属性之间还存在着一定的相关性,这也会增加问题处理的复杂性。
因此,主成分分析(PCA)是一个很好的方法。即利用一组线性无关且维度较低的新特征来代替原始的采样数据。
主成分分析的目标是,减少研究对象数据维度,简单的来说就是降维,但是在降维过程中尽量减少不可避免的信息损失。
二、降维目标
1. 目标数据维度减小,减少特征属性
2. 描述数据的信息损失尽可能少,数据降维一定伴随数据的损失,应当控制尽可能少。
三、PCA主要思路
既然要降低数据维度,那么能不能直接从数据里面挑一个特征属性,直接去掉呢?答案是不行的。因为特征属性之间是存在耦合关系的,也就是说有的属性之间是存在彼此关联的关系的,如此鲁莽的丢弃特征属性进行分析,会对分析结果产生巨大的影响。
基于以上现象,思路有两点:
1. 考虑消除属性之间的关联性(相关性),想办法找一组彼此不相关的新特征来描述数据。
2. 在找到彼此无关的新特征中,进一步舍弃掉不重要的特征,保留较少的特征,实现数据的降维,尽可能保证信息较少地损失。
四、构造无关新特征
以以下表格所示的样本为例子:
随机5个样本结果表 sample1 sample2 sample3 sample4 sample5 X 2 2 4 8 4 Y 2 6 6 8 8
接下来我们要干的事就是寻找两个新的特征来对原始的X和Y进行描述,且这两个新特征要满足彼此无关的要求。就必须让这两个新特征的协方差 = 0 。构成协方差矩阵是一个对角矩阵。现在原始X和Y的协方差不为 0 ,协方差矩阵是一个普通的对称矩阵。
接下来有协方差的定义式子:
经过观察上面式子发现如果将X与Y的均值变成0,协方差的式子得以简化。
将X中的每一个变量都减去均值 μ ,将Y中的每一个变量都减去均值 v 。经过零均值化处理(将时间序列中的每一个值都减去平均值,新序列平均值为0)之后,特征X与特征Y的平均值都变成了0 。这样子处理不会改变方差与协方差的值,不会改变数据离散程度。零均值化处理之后,X与Y协方差矩阵写作:
通过观察可以看到是零均值化处理之后的矩阵与自身的转置矩阵相乘的结果。
即协方差矩阵:
接下来,我们回到原始的目标,就是把各个样本的特征X和特征Y的取值用另一组基来表示,也就是上面说的寻找两个新的特征来对原始的X和Y进行描述,且由于要满足新的基下表示的新特征彼此线性无关,所以选择的两个基必须满足彼此正交(这里不展开证明)。
我们现在假设有一组新的基:和,模长均为1,满足彼此正交。此时,如果用与向量 的点积就表示 在 方向上的投影,由于 是单位向量,那么结果代表基向量的坐标。
那么 与 构成的新基底的坐标是: 。如果令 ,可以进一步表示为:。
那么,表示n个样本的特征X与特征Y的原始采样值。
而. 其中. 表示的是n个样本在新构建的特征下的取值。
现在,尝试让两个新特征 与 满足线性无关。
也就是说,使这两个新特征的协方差为0。那么这个协方差矩阵一定是一个对角矩阵,那么我们现在就可以把问题转化为:
寻找让协方差矩阵C对角化的矩阵P。
由一个重要结论:对称矩阵一定可以得到一组由标准正交特征向量构成特征矩阵Q。
所以有式子,
有。
有
将 与 进行类比,可以发现我们想要的转化矩阵 。
最后,通过乘法运算 就能计算出彼此线性无关的新特征。
五、实际操作
1.零均值化处理:
import numpy as np x = [2,2,4,8,4] y = [2,6,6,8,8] x = x-np.mean(x) #减去x的平均数 y = y-np.mean(y) #减去y的平均数 S = np.vstack((x,y)) print(S) #零均值化后的数据矩阵 print(np.cov(S)) #协方差矩阵
结果:
[[-2. -2. 0. 4. 0.] [-4. 0. 0. 2. 2.]] [[6. 4.] [4. 6.]]
2.求协方差矩阵特征值、特征向量
特征向量→特征矩阵→对角化
import numpy as np from scipy import linalg C = np.array([[6,4],[4,6]]) evalue, evector = linalg.eig(C) #求解特征值和特征矩阵 print(evalue) print(evector)
结果:
[10.+0.j 2.+0.j] [[ 0.70710678 -0.70710678] [ 0.70710678 0.70710678]]
由此,得到两个线性无关的特征投影基,协方差C = 的特征矩阵是Q =
然后再对对角化矩阵进行求解
3.对角化
4.舍弃多余特征
在上面操作中,得到两个新特征。
原始X与Y特征分别在x轴与y轴正方向,两个原始特征彼此相关。
新构造的两个特征在这两个方向上协方差为0,满足彼此线性无关。
最后将新特征投影到原始特征上,就得到新的一组特征取值。
import numpy as np x = [2,2,4,8,4] y = [2,6,6,8,8] x = x-np.mean(x) #减去x的平均数 y = y-np.mean(y) #减去y的平均数 A = np.vstack((x,y)) p_1 = [0.707,0.707] p_2 = [-0.707,0.707] P = np.vstack((p_1,p_2)) print(A) print(np.dot(P,A)) #将P投影到A方向获取新的特征值
结果:
[[-2. -2. 0. 4. 0.] [-4. 0. 0. 2. 2.]] [[-4.242 -1.414 0. 4.242 1.414] [-1.414 1.414 0. -1.414 1.414]]
以上结果
[[-4.242 -1.414 0. 4.242 1.414]
[-1.414 1.414 0. -1.414 1.414]]就是新的到的彼此线性无关的新特征,我们可以在此基础上再进行降维,将二维数据变成一维数据。由于彼此线性无关,所以我们可以保留一组数据,丢掉一组数据。
保留与丢弃的判断依据是方差,方差越大,数据分布程度越大,特征所包含的信息量越大。所以我们应该保留信息量(方差)较大的一组数据。
方向上的特征对应方差是2.5,方向上的特征对应方差是0.5。所以保留前者的特征取值。
最终5个样本用一维数据描述是[-4.242 -1.414 0. 4.242 1.414],从而实现了数据的降维。
5.贡献率——衡量信息的损失程度
原本一共有两个原始特征,保留第一组作为主成分,用方差来衡量主成分贡献率为:
由此可见,在数据压缩过程中,从二维压缩到了一维,压缩了50%,但是保留了83.3%的数据。
六、n个特征降维的情况
假设现在有n个特征。
(1)针对采样得到的m个样本,得到n X m 规模的数据矩阵A
(2)对于每一个特征的样本取值,进行零均值化处理,如果不在一个数量级还要 / 标准差σ
(3)求n个特征的协方差矩阵:
(4)对协方差矩阵C进行对角化,求得协方差矩阵C的n个标准正交特征向量,按照大小排列。
(5)按照主成分贡献率,取满足要求前k个新特征作为主成分,构成数据压缩矩阵
(6)通过投影 PA 实现k个主成分提取,将n维数据压缩到k维,实现主成分提取。