本文给出 PCA最大方差理论求解方法.
配套代码, 请参考文章 :
纯Python和scikit-learn对比实现PCA特征降维
系列文章索引 :
https://blog.csdn.net/oBrightLamp/article/details/85067981
对于给定的一组数据点, 以矩阵 X m × n X_{m \times n} Xm×n 表示 :
X = ( X 1 , X 2 , ⋯   , X m ) T X = (X_1, X_2,\cdots,X_m)^T X=(X1,X2,⋯,Xm)T
X i X_i Xi 为行向量, 中心化后的表示为 :
M m × n = ( X 1 − μ 1 , X 2 − μ 2 , X 3 − μ 3 , ⋯   , X m − μ m ) T M_{m \times n}= (X_1-\mu_1,X_2-\mu_2,X_3-\mu_3,\cdots,X_m-\mu_m)^T Mm×n=(X1−μ1,X2−μ2,X3−μ3,⋯,Xm−μm)T
其中 μ i \mu_i μi 是 X i X_i Xi 的平均值
μ i = m e a n ( X i ) = 1 n ∑ j = 1 j = n x i j \mu_i=mean(X_i) = \frac{1}{n}\sum_{j = 1}^{j = n}x_{ij} μi=mean(Xi)=n1j=1∑j=nxij
行向量 M i M_i Mi 的均值
μ i ′ = m e a n ( M i ) = 1 n ∑ j = 1 j = n m i j = 1 n ∑ j = 1 j = n ( x i j − μ i ) = 0 \mu'_i = mean(M_i) = \frac{1}{n}\sum_{j = 1}^{j = n}m_{ij}= \frac{1}{n}\sum_{j = 1}^{j = n}(x_{ij} - \mu_i) = 0 μi′=mean(Mi)=n1j=1∑j=nmij=n1j=1∑j=n(xij−μi)=0
行向量 M i M_i Mi 在单位行向量 w w w 方向上的长度
l i = M i ⋅ w l_i = M_i\cdot w li=Mi⋅w
l i l_i li 是标量, 符号 ⋅ \cdot ⋅ 表示点积, 投影后的方差 (标量) 可表示为
s = 1 n ∑ i = 1 n ( l i − μ i ′ ) 2 = 1 n ∑ i = 1 n l i 2 = 1 n ∑ i = 1 n ( M i ⋅ w ) 2 s = \frac{1}{n}\sum_{i=1}^{n}{(l_i-\mu'_i) ^2}= \frac{1}{n}\sum_{i=1}^{n}{l_i^2}= \frac{1}{n}\sum_{i=1}^{n}{(M_i\cdot w)^2} s=n1i=1∑n(li−μi′)2=n1i=1∑nli2=n1i=1∑n(Mi⋅w)2
按照 PCA 的最大方差理论, 我们需要求得一个行向量 w w w 使得 s s s 的值最大.
使用向量乘法表示 s s s :
s = 1 n ∑ i = 1 n ( M i ⋅ w ) ( M i ⋅ w ) = 1 n ∑ i = 1 n ( w M i T ) ( M i w T ) s = \frac{1}{n}\sum_{i=1}^{n}{(M_i\cdot w)(M_i\cdot w)}=\frac{1}{n}\sum_{i=1}^{n}{(w M_i^T)(M_iw^T)} s=n1i=1∑n(Mi⋅w)(Mi⋅w)=n1i=1∑n(wMiT)(MiwT)
向量乘法满足结合律 :
s = 1 n ∑ i = 1 n w ( M i T M i ) w T s =\frac{1}{n}\sum_{i=1}^{n}{w(M_i^T M_i)w^T} s=n1i=1∑nw(MiTMi)wT
向量乘法满足分配率 :
s = w ∑ i = 1 n ( 1 n M i T M i ) w T s =w\sum_{i=1}^{n}(\frac{1}{n}M_i^T M_i)w^T s=wi=1∑n(n1MiTMi)wT
令 :
A = ∑ i = 1 n ( 1 n M i T M i ) A =\sum_{i=1}^{n}(\frac{1}{n}M_i^TM_i) A=i=1∑n(n1MiTMi)
则 :
s = w A w T s =w A w^T s=wAwT
A 是样本的协方差矩阵. 若存在特征值 λ \lambda λ (标量), 使得:
A w = λ w Aw = \lambda w Aw=λw
则 :
s = λ w T w = λ ⋅ 1 = λ s =\lambda w^T w = \lambda \cdot1 = \lambda s=λwTw=λ⋅1=λ
问题简化为如何求 A 的最大特征值.
若矩阵 A 有多个特征值, 将这些特征值从大到小排序, 取其中的前 d 个特征值所对应的行向量 V i V_i Vi 组成变换矩阵 :
V d × n = ( V 1 , V 2 , V 3 , ⋯   , V d ) T V_{d\times n}=(V_1,V_2,V_3,\cdots,V_d)^T Vd×n=(V1,V2,V3,⋯,Vd)T
则矩阵 X m × n X_{m \times n} Xm×n 经 PCA 降维后的矩阵为 Z m × d Z_{m \times d} Zm×d
Z m × d = M m × n V d × n T Z_{m\times d} = M_{m\times n}V_{d\times n}^T Zm×d=Mm×nVd×nT
本文仅给出半推导半描述的过程, 用于理解PCA降维的理论和计算机程序编写已经足够.
推导过程参考自《百面机器学习》一书, 更严格的数学证明请参考其他资料.
PCA 降维是一种有损压缩的方法, 《百面机器学习》中使用特征值 λ \lambda λ 定义降维后的信息占比:
η = ∑ i = 1 d λ i 2 ∑ i = 1 n λ i 2 \eta = \sqrt{\frac{\sum_{i=1}^{d}\lambda_i^2}{\sum_{i=1}^{n}\lambda_i^2}} η=∑i=1nλi2∑i=1dλi2
本文作者使用纯Python 和 scikit-learn 对比实现 PCA 降维方法后, 发现 scikit-learn 中 PCA 类的参数 n_components 使用下式定义降维后的信息占比 :
γ = η 2 = ∑ i = 1 d λ i 2 ∑ i = 1 n λ i 2 \gamma = \eta^2=\frac{\sum_{i=1}^{d}\lambda_i^2}{\sum_{i=1}^{n}\lambda_i^2} γ=η2=∑i=1nλi2∑i=1dλi2
相关的数值保存在 explained_variance_ratio_ 属性中.
从特征值的定义可知 :
A w = λ w = − λ ( − w ) Aw = \lambda w=-\lambda(-w) Aw=λw=−λ(−w)
不同的函数库对特征值的求解方法不同, 最后得到的特征向量, 可能出现长度一致但方向相反的情况.
根据 PCA 降维方法的理论和机制, 我们的目的是求解一个降维的拟合平面, 对组成该降维平面向量方向并无要求, 只要在同一直线上即可.
因此, 降维向量出现数值一致, 正负符号相反的情况并不影响 PCA 方法的正常使用.
numpy 的 svd 方法会自动对输入的矩阵 M M M 进行 M T M M^TM MTM 变换后再求特征值, 并自动将特征值从大到小排序.
numpy 的 eig 方法返回的特征值不排序, 需要自行处理.
推荐使用 svd 方法.