机器学习:PCA 降维

参考文章:

【20250527发现已失效】~~http://blog.codinglabs.org/articles/pca-tutorial.html~~

https://zhuanlan.zhihu.com/p/37777074

在学习的过程中发现线性代数的知识非常重要,回顾了一下考研期间看的线性代数的本质:https://www.bilibili.com/video/BV1Ys411k7yQ

选择不同的基可以对同样一组向量给出不同的表示,而且如果基的数量少于向量本身的维数,则可以达到降维的效果。

去均值化(去中心化)

数据中的每一个特征中的数据都减去其平均值。

二维降为一维:投影与方差

以二维降维至一维为例,我们希望在选择这个基后,所有的点在这个基的方向上的投影值尽可能分散,因为如果过于紧凑的话说明特征在该维度上的不同值没有差别,从而丢失了该特征所记录的信息。

量化分散的程度:方差,在进行均值化后,由于平均数为 0,计算方差时可以直接使用

Var(a)=1mi=1mai2Var(a) = \frac{1}{m}\sum^m_{i=1}a_i^2

于是乎,寻找基地的依据就是要尽可能地使方差变大。

三维降为二维:协方差与协方差矩阵

协方差 Covariance

在选择了一个方向(基)后,在选择另一个方向时,我们不能再单纯地选择方差最大的方向,因为这会和第一个方向几乎重合在一起,我们希望他们之前尽可能地线性无关,可以用协方差来量化 相关性,当协方差为 0 时,表示两个字段完全独立。为了让两个基向量完全线性无关,我们选择第二个基时只能在与第一个基正交的方向上选择。最终选择的两个方向一定是正交的:

Cov(a,b)=1mi=1m(aiaˉ)(bibˉ)Cov(\vec a,\vec b) = \frac{1}{m}\sum_{i=1}^m({a_i}-\bar{a})(b_i-\bar{b})

对于去中心化的向量,**由于每个特征均值均为 00,**协方差的计算可以直接使用下面的式子,将所有数据的特征 aa 的值构成一个列向量 a\vec{a},等价于计算 a\vec{a}b\vec{b} 的内积然后除以样本的数量:

Cov(a,b)=1mi=1maibiCov(\vec a,\vec b) = \frac{1}{m}\sum_{i=1}^ma_ib_i

Note

内积的几何本质a\vec ab\vec b 方向上的投影长度乘以 b\vec b 的长度。如果 b\vec b 是一个单位向量,则表示 a\vec ab\vec b 上的投影长度;

a\vec ab\vec b 的协方差为 0 的时候,则说明 a\vec ab\vec b 上的投影长度为 0 或 b\vec b 的长度为 0,表明 a\vec ab\vec b 正交,故他们线性无关;

协方差矩阵

协方差矩阵是为了方便计算出各个特征之间的协方差,对于已经去中心化的特征矩阵 XX

X=(a1a2a3...anb1b2b3...bn...)X = \left( \begin{array}{l} a_1 & a_2 & a_3 & ... & a_n \\ b_1 & b_2 & b_3 & ... & b_n \\ ... \end{array} \right)

XX 的特征矩阵 C=1mXXTC = \frac{1}{m}XX^T

设矩阵 XX 大小为 m×nm\times n,即由 nnmm 维列向量组成。 CC 计算出来是一个对称矩阵,对角线为各个字段的方差,C(i,j)C(i, j) 为第 ii 和第 jj 个特征的协方差

🔥 nn 维降到 kk 维:PCA 的目标

将一组 nn 维向量降为 kk 维,其目标是找到 kk 个单位正交基,使得原始数据变换到这组基上后:

  1. 各特征两两间协方差为 00:保证每个各个特征完全线性无关,在最少的维度中存储最多的信息。
  2. 特征内部的方差则尽可能大:保证特征的不同值在这些基上仍有显著差别。

对角化

设:

  • 原始矩阵对应的协方差矩阵为 CC
  • PP 是一种变换,XX 在降维变换后得到 YY,即 Y=PXY=PX
  • YY 的协方差矩阵为 DD

可以推导出 DDCC 的关系:D=PCPTD=PCP^T

D=1mYYT计算中心化后的矩阵的协方差=1m(PX)(PX)T代入Y=PX=1mPXXTPT=P(1mXXT)PT1mXXT是经过中心化后的矩阵X的协方差矩阵C=PCPT\begin{aligned} D &= \frac{1}{m}YY^T &\text{计算中心化后的矩阵的协方差}\\ &= \frac{1}{m}(PX)(PX)^T &\text{代入}Y=PX\\ &= \frac{1}{m}PXX^TP^T &\\ &= P(\frac{1}{m}XX^T)P^T & \frac{1}{m}XX^T \text{是经过中心化后的矩阵} X \text{的协方差矩阵} C\\ &= PCP^T& \end{aligned}

由 PCA 的优化目标可得,降维后的矩阵的协方差矩阵 DD 要求除了对角元素外的元素均为 00

  • 各特征的方差尽可能选择尽可能大的,故让对角元素从上往下大小递减
  • 降维后不同特征之间协方差为 0,故只有对角线元素不为 0

DD 是对角矩阵。

由上可知,DD 可视为 CC 对角化后的一个对角矩阵,优化目标变成了寻找一个正交矩阵 P(P1=PT)P (P^{-1}=P^T) ,满足PCPTPCP^T是一个对角矩阵,并且对角元素按从大到小依次排列,那么 PP 的前 kk 行就是要寻找的基,用 PP 的前 kk 行组成的矩阵乘以 XX 就使得 XXnn 维降到了 kk 维并满足 PCA 的目标。

由于 CC 作为协方差矩阵,必然是实对称的,也就必然可以用正交矩阵进行对角化,所以:

  • 可以直接通过计算特征向量来得到变换 PPCC 的特征向量作为 PP 的每一列)
  • PCPTPCP^T 的结果就是响应的特征值作为对角元素的对角矩阵就是符合PCA目标的 DD

有了 PP 之后我们就可以用 Y=PXY=PXXX 进行降维

Note

矩阵的对角化

在处理对称矩阵(如协方差矩阵)时,我们常将其对角化。

AA 对角化的时候,就是找到其所有的特征向量作为变化 PP(要求所有特征向量互相线性无关),然后其对应的特征值摆在对角线上就是其对角化后的矩阵 DD

A=PDP1A = P D P^{-1}

其中 DD 是一个对角矩阵,PP 是可逆矩阵。对角线元素是 AA 的特征值的矩阵可以作为 DD

📌 常见要求:将特征值按从大到小排序,依次排列在对角线:λ1λ2λn\lambda_1 \geq \lambda_2 \geq \cdots \geq \lambda_n

  • 方便选取“最重要”的方向(如 PCA 中的主成分);
  • 排名清晰,数值稳定性好;
  • 一些算法依赖特征值的有序性(比如截断选择前 kk 个分量)。

实对称矩阵的特征向量可以构成一个正交矩阵 QQ,满足:

A=QDQA = Q D Q^\top

其中:

  • QQ:由单位正交的特征向量组成,是正交矩阵
  • DD:对角矩阵,对角线上是特征值

Python 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# @author microven @date 2023.3.31
import numpy as np
from sklearn.decomposition import PCA

# 目标维度
target = 1
x = np.array([[-1, -2], [-1, 0], [0, 0], [2, 1], [0, 1]])
# 零均值化
x = x.astype("float64")
x_mean = np.mean(x, axis=0)
x -= x_mean
# 计算协方差矩阵
x_t = np.transpose(x)
cov = np.matmul(x_t, x) / x.shape[0]
# 计算协方差矩阵的特征值
eigen, feature = np.linalg.eig(cov)
# 确定 top k 特征值
sorted_index = np.argsort(eigen)[::-1]
# 根据 top k 特征值取出其特征向量
top_k = np.array([feature[:, sorted_index[0]]])
for i in range(1, target):
top_k = np.append(top_k, feature[:, sorted_index[i]])
result_x = np.matmul(x, np.transpose(top_k))
print(result_x)