深入理解PCA(主成分分析法)算法

问题引入

现有某商店分析影响销售额的因素有哪些,做了以下调查。
日期 x 1 \textbf{x}_1 x12679
空气质量 x 2 \textbf{x}_2 x210603090
上班时间 x 3 \textbf{x}_3 x38897

假装目前这三个影响因素太多,需要降维处理。
原始思想
如果要降到2维,最直接的做法就是将其中一个因素 x i \textbf{x}_i xi去除,然后分析剩余的两个,但是这种做法过于粗暴,是否存在一种更加合理的方法去处理。


符号声明

x i \textbf{x}_i xi代表表格中第i行, x j \textbf{x}_j xj代表表格中第j列, x i j x_{ij} xij代表矩阵中第(i,j)个元素,其中 i = 1 , 2 , ⋯   , m ; j = 1 , 2 , ⋯   , n i=1,2,\cdots,m;j=1,2,\cdots,n i=1,2,,m;j=1,2,,n

基本思想

方案一
求出每个因素 x i \textbf{x}_i xi的方差
方差公式 s i 2 = 1 n − 1 ∑ j = 1 n ( x i j − x ‾ i ) 2 s_i^2=\frac{1}{n-1}\sum_{j=1}^{n}(x_{ij}-\overline\textbf{x}_i)^2 si2=n11j=1n(xijxi)2
从概率上来说方差可以反应数值的分散程度,对于分散程度较小的因素而言(极端情况为一个不变的数值)说明分析的价值不大,所以可以舍弃。(ps:有人从熵的角度去解释,但是本人目前没有接触该方面的知识,以后会补上)
方案二
但是由于各类因素是充满联系的,比如说空气质量可能会影响上班时间,一些方差小的原因可能不是该因素本身的原因,而是其它因素影响造成的,需要将这些因素之间的影响去除掉,在除掉之前先引进协方差的概念。
向量 x i \textbf{x}_i xi与向量 y i \textbf{y}_i yi之间的协方差为
c o v ( x i , y i ) = 1 n − 1 ∑ j = 1 n ( x i j − x ‾ i ) ( y i j − y ‾ i ) cov(\textbf{x}_i,\textbf{y}_i)=\frac{1}{n-1}\sum_{j=1}^{n}(x_{ij}-\overline{x}_i)(y_{ij}-\overline{y}_i) cov(xi,yi)=n11j=1n(xijxi)(yijyi)

为方便求解,将 x i \textbf{x}_i xi y i \textbf{y}_i yi分别进行去中心化(将向量中的每个元素减去平均值)处理
x i = x i − x ‾ i \textbf{x}_i=\textbf{x}_i-\overline\textbf{x}_i xi=xixi
y i = y i − y ‾ i \textbf{y}_i=\textbf{y}_i-\overline\textbf{y}_i yi=yiyi
此时,协方差公式简化为
c o v ( x i , y i ) = 1 n − 1 ∑ j = 1 n x i j y i j = 1 n − 1 x i T y i cov(\textbf{x}_i,\textbf{y}_i)=\frac{1}{n-1}\sum_{j=1}^n\textbf{x}_{ij}\textbf{y}_{ij}=\frac{1}{n-1}\textbf{x}_i^T\textbf{y}_i cov(xi,yi)=n11j=1nxijyij=n11xiTyi
协方差可以反应两个向量之间的相关性:
当cov(X,Y)<0时,两者负相关。
当cov(X,Y)=0时,两者不相关。
当cov(X,Y)>0时,两者正相关。
ps:相关性与独立性不是一个概念。
不同因素之间的相关性可以利用协方差矩阵 C \textbf{C} C来表示,具体公式如下:
C = [ c o v ( x 1 , x 1 ) c o v ( x 1 , x 2 ) ⋯ c o v ( x 1 , x n ) c o v ( x 2 , x 1 ) c o v ( x 2 , x 2 ) ⋯ c o v ( x 2 , x n ) ⋮ ⋮ ⋱ ⋮ c o v ( x m , x 1 ) c o v ( x m , x 1 ) ⋯ c o v ( x m , x m ) ] = 1 n − 1 ∑ j = 1 n x j x j T \textbf{C}=\begin{bmatrix} cov(x_1,x_1)&cov(x_1,x_2)&\cdots&cov(x_1,x_n)\\ cov(x_2,x_1)&cov(x_2,x_2)&\cdots&cov(x_2,x_n)\\ \vdots&\vdots&\ddots&\vdots\\ cov(x_m,x_1)&cov(x_m,x_1)&\cdots&cov(x_m,x_m) \end{bmatrix}=\frac{1}{n-1}\sum_{j=1}^{n}\textbf{x}_j\textbf{x}_j^T C=cov(x1,x1)cov(x2,x1)cov(xm,x1)cov(x1,x2)cov(x2,x2)cov(xm,x1)cov(x1,xn)cov(x2,xn)cov(xm,xm)=n11j=1nxjxjT
对于问题中的三个变量之间的关系,可以利用协方差矩C来表达(等式右边很关键,可以自行推导或验证),如下:
C = [ c o v ( x 1 , x 1 ) c o v ( x 1 , x 2 ) c o v ( x 1 , x 3 ) c o v ( x 2 , x 1 ) c o v ( x 2 , x 2 ) c o v ( x 2 , x 3 ) c o v ( x 3 , x 1 ) c o v ( x 3 , x 2 ) c o v ( x 3 , x 3 ) ] = 1 4 − 1 ∑ j = 1 4 x j x j T C=\left[ \begin{matrix} cov(x_1,x_1)&cov(x_1,x_2)&cov(x_1,x_3)\\ cov(x_2,x_1)&cov(x_2,x_2)&cov(x_2,x_3)\\ cov(x_3,x_1)&cov(x_3,x_2)&cov(x_3,x_3) \end{matrix} \right] =\frac{1}{4-1}\sum_{j=1}^{4}\textbf{x}_j\textbf{x}_j^T C=cov(x1,x1)cov(x2,x1)cov(x3,x1)cov(x1,x2)cov(x2,x2)cov(x3,x2)cov(x1,x3)cov(x2,x3)cov(x3,x3)=411j=14xjxjT
协方差矩阵对角线位置上的数值表示方差,非对角线位置上的数值表示各因素之间的相关性,假设存在一个协方差矩阵D为对角矩阵,形式如下
D = [ c o v ( y 1 , y 1 ) 0 0 0 c o v ( y 2 , y 2 ) 0 0 0 c o v ( y 3 , y 3 ) ] = 1 4 − 1 ∑ j = 1 4 y j y j T D=\begin{bmatrix} cov(y_1,y_1)&0&0\\ 0&cov(y_2,y_2)&0\\ 0&0&cov(y_3,y_3) \end{bmatrix}=\frac{1}{4-1}\sum_{j=1}^{4}\textbf{y}_j\textbf{y}_j^T D=cov(y1,y1)000cov(y2,y2)000cov(y3,y3)=411j=14yjyjT
此时就可以按照改进一中的方案利用方差的大小进行降维。
为使各个因素之间不相关,需要一种方法对各个因素进行坐标转换使协方差矩阵转换为对角矩阵 ***(记住这一求解目标)***。可以看到协方差矩阵C是一个对称矩阵,线性代数的知识表明,可以将C进行坐标变换,使各个元素在新的坐标系中不相关,下面进行这一方面的推导,这个推导过程实际上就是PCA的产生过程。


投影

向量X与向量Y的点乘公式如下
X ⋅ Y = ∣ ∣ X ∣ ∣ ∣ ∣ Y ∣ ∣ c o s < X , Y > \textbf{X}\cdot\textbf{Y}=||\textbf{X}||||\textbf{Y}||cos<\textbf{X},\textbf{Y}> XY=XYcos<X,Y>
以二维平面为例
在这里插入图片描述
向量X在向量Y上投影的长度可以表示为
∣ ∣ X ∣ ∣ c o s < X , Y > ||\textbf{X}||cos<\textbf{X},\textbf{Y}> Xcos<X,Y>
cos<X,Y>的大小仅仅与X与Y的夹角有关,所以X在Y上的投影可以表达为
X ⋅ e y = e y T X \textbf{X}\cdot\textbf{e}_y=\textbf{e}_y^T\textbf{X} Xey=eyTX
其中 e y \textbf{e}_y ey表示与Y同方向的单位向量。

坐标变换

坐标系上点的坐标是该点在各个坐标中上的投影,利用这一概念对坐标系中的点进行坐标变换。
以二维坐标为例, e 1 e_1 e1 e 2 e_2 e2是平面坐标系中的两个正交向量(也称为正交基),点a在坐标系中的位置为 ( 1 , 1 ) T (1,1)^T (1,1)T,求点a在 e 1 e_1 e1 e 2 e_2 e2组成的坐标系中的位置。
在这里插入图片描述

首先对 e 1 e_1 e1 e 2 e_2 e2单位化处理
e 1 = ( 2 5 , 1 5 ) T e_1=(\frac{2}{\sqrt{5}},\frac{1}{\sqrt{5}})^T e1=(5 2,5 1)T
e 2 = ( − 1 5 , 2 5 ) T e_2=(-\frac{1}{\sqrt{5}},\frac{2}{\sqrt{5}})^T e2=(5 1,5 2)T
此时 e 1 与 e 2 e_1与e_2 e1e2是单位向量且正交,像这样一组为单位向量且两两正交的向量被称为标准正交基。
利用投影可以求出点P在新坐标中的位置。
a在 e 1 e_1 e1上的投影距离为
e 1 T a = 3 5 e_1^Ta=\frac{3}{\sqrt{5}} e1Ta=5 3
a在 e 2 e_2 e2上的投影距离为
e 2 T a = 1 5 e_2^Ta=\frac{1}{\sqrt{5}} e2Ta=5 1
写成矩阵表达式为
[ e 1 T e 2 T ] a \left[ \begin{matrix} e_1^T\\ e_2^T \end{matrix} \right]a [e1Te2T]a
a在新的坐标下的坐标为 ( 3 5 , 1 5 ) (\frac{3}{\sqrt{5}},\frac{1}{\sqrt{5}}) (5 3,5 1)
在m维空间中,令 P = [ e 1 e 2 ⋯ e m ] \textbf{P}=\begin{bmatrix}e_1&e_2&\cdots&e_m\end{bmatrix} P=[e1e2em],求 x \textbf{x} x P \textbf{P} P组成的m维标准正交基中的坐标公式如下
[ e 1 e 2 ⋯ e m ] T x = P T x \begin{bmatrix} e_1&e_2&\cdots&e_m \end{bmatrix}^T\textbf{x}=\textbf{P}^T\textbf{x} [e1e2em]Tx=PTx


证明过程

我们的目标是通过坐标变换的方式找到一个为对角矩阵协方差矩阵,为证明这一目标,不妨假设存在左边转换 y j = P T x j \textbf{y}_j=\textbf{P}^T\textbf{x}_j yj=PTxj使协方差矩阵C转换为对角矩阵D,推导过程如下
D = 1 n − 1 ∑ j = 1 n y j y j T = 1 n − 1 ∑ j = 1 n P T x j x j T P = 1 n − 1 P T ( ∑ j = 1 n x j x j T ) P = 1 n − 1 P T C P (推导1) \begin{matrix} \begin{aligned} D&=&\frac{1}{n-1}\sum_{j=1}^n\textbf{y}_j\textbf{y}_j^T\\ &=&\frac{1}{n-1}\sum_{j=1}^n\textbf{P}^T\textbf{x}_j\textbf{x}_j^T\textbf{P}\\ &=&\frac{1}{n-1}\textbf{P}^T(\sum_{j=1}^n\textbf{x}_j\textbf{x}_j^T)\textbf{P}\\ &=&\frac{1}{n-1}\textbf{P}^TC\textbf{P} \end{aligned} \end{matrix}\tag{推导1} D====n11j=1nyjyjTn11j=1nPTxjxjTPn11PT(j=1nxjxjT)Pn11PTCP(1)
ps:不知道为什么\begin{align}\end{align}报错,无法左对齐,排版就先凑合看吧。

接下来回顾一下对称矩阵的性质:
1.设 C \textbf{C} C为是n阶实对称矩阵,则必有正交矩阵 P \textbf{P} P,使 P − 1 CP = P T CP \textbf{P}^{-1}\textbf{C}\textbf{P}=\textbf{P}^{T}\textbf{C}\textbf{P} P1CP=PTCP为对角矩阵 D \textbf{D} D,且D中主对角线上的元素为 C \textbf{C} C的特征值,它们的排列次序与对应于他们的特征向量在 P \textbf{P} P中的排列次序一致。
2.实对称矩阵的k重特征值所对应的线性无关的特征向量恰好有k个。
3.实对称矩阵的相异特征值所对应的特征向量是正交的。
由于C为对称矩阵,根据对称矩阵的性质则一定存在矩阵P使 P T CP \textbf{P}^T\textbf{C}\textbf{P} PTCP变为对角矩阵,改进二中提出的目标得以证明。
接下来只需要保留方差较大的 y i \textbf{y}_i yi即可,由上面的推导(1)以及性质1可知,坐标转换之后的协方差矩阵 D \textbf{D} D是一个对角矩阵,并按照方差(根据性质3以及推导(1)可以看出方差就是 C \textbf{C} C的特征值)从大向小的顺序排列如下:
D m × m = [ ∑ j = 1 n y 1 j 2 0 ⋯ 0 0 ∑ j = 1 n y 2 j 2 ⋯ 0 ⋮ ⋮ ⋱ ⋮ ⋯ ⋯ ∑ j = 1 n y k j 2 ⋯ ⋮ ⋮ ⋱ ⋮ 0 0 ⋯ ∑ j = 1 n y m j 2 ] \textbf{D}_{m×m}=\begin{bmatrix} \sum_{j=1}^n\textbf{y}_{1j}^2&0&\cdots&0\\ 0&\sum_{j=1}^n\textbf{y}_{2j}^2&\cdots&0\\ \vdots&\vdots&\ddots&\vdots\\ \cdots&\cdots&\sum_{j=1}^n\textbf{y}_{kj}^2&\cdots\\ \vdots&\vdots&\ddots&\vdots\\ 0&0&\cdots&\sum_{j=1}^n\textbf{y}_{mj}^2 \end{bmatrix} Dm×m=j=1ny1j2000j=1ny2j20j=1nykj200j=1nymj2
为方便描述定义转换坐标后的 y i \textbf{y}_i yi分量所对应的原来的基向量(也叫特征向量)为 e i \textbf{e}_i ei,那么 P T = [ e 1 , e 2 , ⋯   , e m ] T \textbf{P}^T=\begin{bmatrix}\textbf{e}_1,\textbf{e}_2,\cdots,\textbf{e}_m\end{bmatrix}^T PT=[e1,e2,,em]T
为保留前k个方差较大的 y \textbf{y} y分量,由 D \textbf{D} D知前k行对应前k个 y i \textbf{y}_i yi分量,只需要保留分量 y 1 , ⋯   , y k \textbf{y}_1,\cdots,\textbf{y}_k y1,,yk即可。
由坐标转换公式知
y j = P T x j = [ e 1 , e 2 , ⋯   , e k , ⋯   , e m ] T x j \textbf{y}_j=\textbf{P}^T\textbf{x}_j=\begin{bmatrix}\textbf{e}_1,\textbf{e}_2,\cdots,\textbf{e}_k,\cdots,\textbf{e}_m\end{bmatrix}^T\textbf{x}_j yj=PTxj=[e1,e2,,ek,,em]Txj
由于
y j = [ y 1 j , y 2 j , ⋯   , y k j , ⋯   , y m j ] \textbf{y}_j=\begin{bmatrix}{y}_{1j},{y}_{2j},\cdots,{y}_{kj},\cdots,{y}_{mj}\end{bmatrix} yj=[y1j,y2j,,ykj,,ymj]
现需要保留分量 y 1 , ⋯   , y k \textbf{y}_1,\cdots,\textbf{y}_k y1,,yk,所以直接取前k个元素 y 1 j , y 2 j , ⋯   , y k j {y}_{1j},{y}_{2j},\cdots,{y}_{kj} y1j,y2j,,ykj即可。
为了方便计算通常将较小的方差(特征值)对应的特征向量 e k + 1 , ⋯   , e m \textbf{e}_{k+1},\cdots,\textbf{e}_m ek+1,,em剔除,计算公式如下
y j = P T x j = [ e 1 , e 2 , ⋯   , e k ] T x j \textbf{y}_j=\textbf{P}^T\textbf{x}_j=\begin{bmatrix}\textbf{e}_1,\textbf{e}_2,\cdots,\textbf{e}_k\end{bmatrix}^T\textbf{x}_j yj=PTxj=[e1,e2,,ek]Txj


算法步骤

最后总结将PCA降维步骤如下:
1).将 x i \textbf{x}_i xi去中心化
x i = x i − x ‾ i \textbf{x}_i=\textbf{x}_i-\overline\textbf{x}_i xi=xixi
2).计算协方差矩阵C。
C = 1 n − 1 x x T \textbf{C}=\frac{1}{n-1}\textbf{x}\textbf{x}^T C=n11xxT
实际上系数 1 n − 1 \frac{1}{n-1} n11仅仅涉及到最终计算出来的方差的倍数,并不影响方差之间的比例以及大小,所以去掉也不会对结果有任何影响,为了减少计算量常常写作
C = x x T \textbf{C}=\textbf{x}\textbf{x}^T C=xxT
3).求出C的全部相异特征值 λ 1 , ⋯   , λ m ˙ \lambda_1,\cdots,\lambda_{\dot{m}} λ1,,λm˙;(有些特征值可能相等, m ˙ ≤ m \dot{m}≤m m˙m
4).对于每一个重特征值 λ i \lambda_i λi,求出对应的 r i r_i ri个线性无关的特征向量 α i 1 , α i 2 , ⋯   , α i r i ( i = 1 , 2 , ⋯   , m ˙ ) \alpha_{i1},\alpha_{i2},\cdots,\alpha_{ir_i}(i=1,2,\cdots,\dot{m}) αi1,αi2,,αiri(i=1,2,,m˙),由性质2知 ∑ i = 1 m ˙ r i = m \sum_{i=1}^{\dot{m}}r_i=m i=1m˙ri=m;(说明正交矩阵P是mxm的)
5).利用施密特正交化方法,把对应于每一个 λ i \lambda_i λi的线性无关特征向量先正交化再单位化,得到一组等价的两两正交的单位向量组 η i 1 , η i 2 , ⋯   , η i r i ( i = 1 , 2 , ⋯   , m ˙ ) \eta_{i1},\eta_{i2},\cdots,\eta_{ir_i}(i=1,2,\cdots,\dot{m}) ηi1,ηi2,,ηiri(i=1,2,,m˙),他们仍为矩阵 P \textbf{P} P对应于 λ i \lambda_i λi的特征向量。(很多博客没有正交化步骤,通过性质3可以知道如果出现相等的特征值,所对应的特征向量不一定正交)
6).将上面求得的正交单位向量作为列向量,排成一个n阶方阵 P \textbf{P} P,则 P \textbf{P} P即为所求的正交矩阵,此时, P T CP = D \textbf{P}^T\textbf{C}\textbf{P}=\textbf{D} PTCP=D
为对角矩阵,D中主对角线上的元素为 C \textbf{C} C的特征值,且它们的排列次序与对应于他们的特征向量在 P \textbf{P} P中的排列次序一致,一般情况下总是按照特征值降序排列特征向量。(很多博客没讲清楚降维时保留较大的特征值对应的特征矩阵的原因,通过改进二我们知道,这是为了保留较大的方差, D \textbf{D} D的对角线为坐标转换后各个影响因素的所对应的方差,同时对角线元素也是矩阵 C \textbf{C} C的特征值,所以保留较大的特征值就是保留较大的方差)。
7).保留特征值较大的特征向量,不知道降低到多少维合适时一般按照经验判断保留到特征值所在比例为95%左右,有时候为了可视化比例可能远低于这个数值,令 P = [ e 1 e 2 ⋯ e k ] ( k ≤ m ) \textbf{P}=\begin{bmatrix}\textbf{e}_1&\textbf{e}_2&\cdots&\textbf{e}_k\end{bmatrix}(k\leq{m}) P=[e1e2ek](km),最终降维之后的坐标为 y j = P T x j \textbf{y}_j=\textbf{P}^T\textbf{x}_j yj=PTxj。(舍弃的 e m + 1 , ⋯   , e n \textbf{e}_{m+1},\cdots,\textbf{e}_n em+1,,en是变换坐标之后的一些不重要的坐标轴,饶了一大圈还是回到了原始思想的粗暴方法中,也就是说如果原始数据的协方差矩阵符合矩阵D的形式,那么按照PCA的思想可以直接去除方差较小的因素)
PCA降维应对大量现实问题时比较合理,但是通过原始思想也可以看出,当求出的特征值(矩阵D对应的方差)变化不明显时,PCA表现效果不会特别如愿。


python代码

现在来处理文章开篇的引出的问题
在这里插入图片描述
附加python代码

import numpy as np 
def myPCA(a,k):
	print('调查表矩阵:')
	print(a)
	assert(isinstance(k,int))
	assert(isinstance(a,np.ndarray))
	ax,ay=a.shape
	assert(k>0 and k<=ay)
	arr_mean=np.array([np.mean(a,axis=1)]).T
	print('每行行平均值:')
	print(arr_mean)
	a=a-arr_mean#去中心化
	print('去中心化后矩阵:')
	print(a)
	#计算协方差矩阵
	arr_c=np.dot(a,a.T)
	print('协方差矩阵:')
	print(arr_c)
	#计算特征值与特征向量,numpy计算的特征向量都是单位化之后的
	eig_value,eig_vec=np.linalg.eig(arr_c)
	print('特征值:')
	print(eig_value)
	print('特征向量,按行排列:')
	print(eig_vec.T)
	#升序排列
	index=np.argsort(eig_value)
	#取最后k个特征向量
	eig_vec_k=eig_vec[:,index[:-k-1:-1]].T
	print('降到%d维后:'%k)
	return np.dot(np.array(eig_vec_k),a)

k=2
a = np.array([[2,6,7,9]
			,[10,60,30,60]
			,[8,8,9,7]])  
print(myPCA(a,k))

调用scikit-learn求解结果以及代码
在这里插入图片描述
第一行与自己写的代码中的结果有着正负上的区别,熟悉线性代数的都知道,一个特征值的单位特征向量有正负两个,两者都是对的。

import numpy as np
from sklearn.decomposition import PCA
a = np.array([[2,6,7,9]
			,[10,60,30,60]
			,[8,8,9,7]])
#n_components降低到的维度
pca=PCA(n_components=2)
#最终结果
print(pca.fit_transform(a.T).T)