主成分分析(Principal Component Analysis,简称PCA)是一种常用的数据降维技术。它主要用于将高维数据映射到低维空间,同时尽可能保留原始数据中的重要信息。PCA 的基本思想是通过正交变换,把由线性相关的变量表示的观测数据转换为少数几个由线性无关变量表示的数据。线性变换将数据投影到新的坐标系中,这个新的坐标系的轴(即主成分)是原始数据中方差最大的方向。下面我会详细解释 PCA 的核心概念和步骤。
核心概念
-
方差:方差是数据分散程度的度量。PCA 希望找到那些使数据方差最大的方向,因为这些方向包含了最多的信息。
-
协方差矩阵:协方差矩阵用于描述数据集中变量之间的关系。通过计算协方差矩阵,可以了解哪些变量之间存在线性关系。
-
特征值和特征向量:协方差矩阵的特征值和特征向量是 PCA 的核心。特征向量代表数据的方向,特征值表示在这些方向上的数据分散程度(方差)。
PCA 的步骤
-
数据中心化:将数据集中的每一个特征减去其均值,使得每个特征的均值为零。这样做的目的是为了消除特征的量纲对结果的影响。
X centered = X − X ˉ X_{\text{centered}} = X - \bar{X} Xcentered=X−Xˉ
其中 X ˉ \bar{X} Xˉ 是数据集 X X X 的均值。
-
计算协方差矩阵:对于中心化后的数据,计算其协方差矩阵。
Cov ( X ) = 1 n − 1 X centered T X centered \text{Cov}(X) = \frac{1}{n-1} X_{\text{centered}}^T X_{\text{centered}} Cov(X)=n−11XcenteredTXcentered
其中 ( n ) 是样本数。
-
计算特征值和特征向量:对协方差矩阵进行特征值分解,得到特征值和特征向量。
Cov ( X ) v = λ v \text{Cov}(X) \mathbf{v} = \lambda \mathbf{v} Cov(X)v=λv
其中 λ \lambda λ 是特征值, v \mathbf{v} v是特征向量。
-
选择主成分:根据特征值的大小排序,选择前 ( k ) 个最大的特征值对应的特征向量,作为主成分。
-
转换数据:将原始数据投影到选定的主成分上,得到降维后的数据。
Y = X centered W Y = X_{\text{centered}} \mathbf{W} Y=XcenteredW
其中 W \mathbf{W} W是选定的特征向量矩阵。
-
矩阵乘法:对于 X centered \mathbf{X}_{\text{centered}} Xcentered中的每一行向量 x i \mathbf{x}_i xi,以及 W \mathbf{W} W中的每一列向量 w j \mathbf{w}_j wj,计算它们的点积 x i ⋅ w j \mathbf{x}_i \cdot \mathbf{w}_j xi⋅wj。
-
新空间表示:这些点积结果就是原始数据在新的坐标系(由主成分定义)中的表示,构成了降维后的数据矩阵 Y \mathbf{Y} Y。
示例代码
以下是一个简单的 PCA 示例代码,使用 numpy 来实现:
import numpy as np
def pca(X, n_components):
# 数据中心化
X_centered = X - np.mean(X, axis=0)
# 计算协方差矩阵
cov_matrix = np.cov(X_centered, rowvar=False)
# 计算特征值和特征向量
eigenvalues, eigenvectors = np.linalg.eigh(cov_matrix)
# 按特征值大小排序
sorted_index = np.argsort(eigenvalues)[::-1]
sorted_eigenvalues = eigenvalues[sorted_index]
sorted_eigenvectors = eigenvectors[:, sorted_index]
# 选择前 n_components 个特征向量
eigenvector_subset = sorted_eigenvectors[:, 0:n_components]
# 转换数据
X_reduced = np.dot(X_centered, eigenvector_subset)
return X_reduced
# 示例使用
X = np.array([[2.5, 2.4],
[0.5, 0.7],
[2.2, 2.9],
[1.9, 2.2],
[3.1, 3.0],
[2.3, 2.7],
[2.0, 1.6],
[1.0, 1.1],
[1.5, 1.6],
[1.1, 0.9]])
X_reduced = pca(X, n_components=1)
print(X_reduced)
这个代码通过以下几个步骤实现了 PCA:
- 数据中心化。
- 计算协方差矩阵。
- 计算特征值和特征向量,并按特征值排序。
- 选择前 n 个特征向量。
- 将原始数据投影到选定的主成分上。
PCA 可以有效地减少数据维度,降低计算复杂度,同时在一定程度上保持数据的主要信息,是处理高维数据的常用方法。
PCA 可以通过两种主要方法实现:协方差矩阵的特征值分解法和奇异值分解法(Singular Value Decomposition, SVD)。这两种方法在最终目的和结果上是一致的,但在计算过程和使用上有所不同。
特征值分解法 vs. 奇异值分解法
-
特征值分解法:
- 计算数据的协方差矩阵。
- 对协方差矩阵进行特征值分解。
- 使用特征向量来投影数据到新空间。
-
奇异值分解法:
- 对中心化的原始数据矩阵进行奇异值分解。
- 使用右奇异向量(V 或 V^T)来投影数据到新空间。
奇异值分解法的具体步骤
-
数据中心化:将数据集中每一个特征减去其均值,使得每个特征的均值为零。
X centered = X − X ˉ X_{\text{centered}} = X - \bar{X} Xcentered=X−Xˉ
-
进行奇异值分解:对中心化后的数据矩阵进行 SVD。
X centered = U Σ V T X_{\text{centered}} = U \Sigma V^T Xcentered=UΣVT
其中:
- U U U 是一个 n × n n \times n n×n 的正交矩阵,列向量称为左奇异向量。
- Σ \Sigma Σ 是一个 n × m n \times m n×m的对角矩阵,包含奇异值。
- V V V 是一个 m × m m \times m m×m的正交矩阵,列向量称为右奇异向量。
-
选择主成分:根据奇异值的大小选择前 k k k个最大的奇异值对应的右奇异向量。
-
转换数据:使用右奇异向量来投影数据到低维空间。
Y = X centered V k Y = X_{\text{centered}} V_k Y=XcenteredVk
其中 V k V_k Vk是选择的前 k k k个右奇异向量组成的矩阵。
示例代码
以下是一个使用奇异值分解实现 PCA 的示例代码:
import numpy as np
def pca_svd(X, n_components):
# 数据中心化
X_centered = X - np.mean(X, axis=0)
# 奇异值分解
U, S, Vt = np.linalg.svd(X_centered, full_matrices=False)
# 选择前 n_components 个右奇异向量
V = Vt.T
principal_components = V[:, :n_components]
# 转换数据
X_reduced = np.dot(X_centered, principal_components)
return X_reduced
# 示例使用
X = np.array([[2.5, 2.4],
[0.5, 0.7],
[2.2, 2.9],
[1.9, 2.2],
[3.1, 3.0],
[2.3, 2.7],
[2.0, 1.6],
[1.0, 1.1],
[1.5, 1.6],
[1.1, 0.9]])
X_reduced = pca_svd(X, n_components=1)
print(X_reduced)
主要区别
-
计算复杂度:
- 特征值分解法:需要计算协方差矩阵,然后对其进行特征值分解。如果数据集很大,这一步的计算和存储可能具有挑战性。
- 奇异值分解法:对数据矩阵直接进行 SVD。对于大型数据集,SVD 可以更高效地处理,而且数值稳定性更好。
-
直接性:
- 特征值分解法:先计算协方差矩阵,这一步可能会失去一些关于数据的细节信息。
- 奇异值分解法:直接对原始数据进行分解,保留了更多的原始数据信息。
-
使用情景:
- 特征值分解法:适合处理协方差矩阵计算容易的数据集。
- 奇异值分解法:在大数据集或协方差矩阵难以处理时,SVD 是更适合的方法。
总的来说,虽然这两种方法本质上都会得到相同的主成分,但在实践中,奇异值分解法往往更加高效和实用。