Python实战:PCA算法原理与代码全解析


第 1 章 引言:为什么要学习 PCA

在数据科学和机器学习中,我们经常会遇到如下问题:

  1. 维度灾难
    数据维度过高会导致计算复杂度增加,模型训练缓慢,甚至出现过拟合。
  2. 特征冗余
    数据集中可能存在大量冗余特征,它们彼此高度相关,导致模型难以捕捉真正的模式。
  3. 可视化困难
    人类直觉主要依赖二维或三维空间,高维数据难以可视化。

为了解决这些问题,降维技术应运而生,而其中最经典、最常用的方法就是 主成分分析(Principal Component Analysis, PCA)

PCA 的核心思想是:

将高维数据映射到一组新的正交基(主成分)上,保留最大方差方向上的信息,从而实现降维、压缩和去噪

应用场景包括:

  • 机器学习预处理:降低维度、加速训练、去除噪声
  • 数据可视化:将高维数据映射到 2D 或 3D
  • 压缩存储:如图像压缩
  • 金融建模:降维后提取核心因子

第 2 章 数学原理解析

PCA 的原理来自于线性代数和概率统计。

2.1 数据中心化

对样本矩阵 $X \in \mathbb{R}^{n \times d}$:

$$ X = \{x_1, x_2, \dots, x_n\}, \quad x_i \in \mathbb{R}^d $$

先做中心化:

$$ X_{centered} = X - \mu, \quad \mu = \frac{1}{n}\sum_{i=1}^n x_i $$

2.2 协方差矩阵

定义样本协方差矩阵:

$$ C = \frac{1}{n-1} X_{centered}^T X_{centered} $$

2.3 特征值分解

对 $C$ 做特征值分解:

$$ C v_i = \lambda_i v_i $$

  • 特征值 $\lambda_i$:对应主成分方向的方差
  • 特征向量 $v_i$:主成分方向

2.4 主成分排序

按特征值大小排序,取前 $k$ 个主成分:

$$ W = [v_1, v_2, \dots, v_k] $$

2.5 数据降维

最终投影公式:

$$ Y = X_{centered} W $$

其中 $Y \in \mathbb{R}^{n \times k}$ 即降维后的新表示。


第 3 章 算法实现流程图

文字版流程:

原始数据 X 
   ↓
数据中心化(减去均值)
   ↓
计算协方差矩阵 C
   ↓
特征值分解 C = VΛV^T
   ↓
选取最大特征值对应的前 k 个特征向量
   ↓
数据投影 Y = X_centered × W

如果用图表示,则 PCA 本质上是把原始坐标系旋转到“最大方差方向”的新坐标系中。


第 4 章 从零实现 PCA

我们先不用 sklearn,而是自己实现。

4.1 数据生成

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(42)
# 生成二维数据(有相关性)
X = np.dot(np.random.rand(2, 2), np.random.randn(2, 200)).T

plt.scatter(X[:, 0], X[:, 1], alpha=0.5)
plt.title("原始数据分布")
plt.show()

4.2 PCA 实现

def my_pca(X, n_components):
    # 1. 数据中心化
    X_centered = X - np.mean(X, axis=0)
    
    # 2. 协方差矩阵
    cov_matrix = np.cov(X_centered, rowvar=False)
    
    # 3. 特征值分解
    eig_vals, eig_vecs = np.linalg.eigh(cov_matrix)
    
    # 4. 排序
    sorted_idx = np.argsort(eig_vals)[::-1]
    eig_vals = eig_vals[sorted_idx]
    eig_vecs = eig_vecs[:, sorted_idx]
    
    # 5. 取前 k 个
    W = eig_vecs[:, :n_components]
    X_pca = np.dot(X_centered, W)
    
    return X_pca, W, eig_vals

X_pca, W, eig_vals = my_pca(X, n_components=1)
print("特征值:", eig_vals)
print("降维后形状:", X_pca.shape)

4.3 可视化主成分

plt.scatter(X[:, 0], X[:, 1], alpha=0.3)
for i in range(W.shape[1]):
    plt.plot([0, W[0, i]*3], [0, W[1, i]*3], linewidth=2, label=f"PC{i+1}")
plt.legend()
plt.axis("equal")
plt.show()

这时能直观看到 PCA 的第一主成分就是数据分布方差最大的方向。


第 5 章 使用 sklearn 实现 PCA

from sklearn.decomposition import PCA

pca = PCA(n_components=1)
X_pca = pca.fit_transform(X)

print("解释方差比:", pca.explained_variance_ratio_)

scikit-learn 内部是基于 SVD 分解 的,更稳定、更高效。


第 6 章 PCA 实战案例

6.1 手写数字可视化

from sklearn.datasets import load_digits

digits = load_digits()
X = digits.data  # 1797 × 64
y = digits.target

pca = PCA(n_components=2)
X_reduced = pca.fit_transform(X)

plt.scatter(X_reduced[:, 0], X_reduced[:, 1], c=y, cmap="tab10", alpha=0.6)
plt.colorbar()
plt.title("手写数字 PCA 可视化")
plt.show()

通过 PCA,64 维的数字图像被映射到 2D 平面,并且仍然能区分出类别分布。


6.2 图像压缩

from sklearn.datasets import load_digits

digits = load_digits()
X = digits.data

pca = PCA(n_components=20)
X_reduced = pca.fit_transform(X)
X_restored = pca.inverse_transform(X_reduced)

fig, axes = plt.subplots(1, 2, figsize=(8, 4))
axes[0].imshow(X[0].reshape(8, 8), cmap="gray")
axes[0].set_title("原始图像")
axes[1].imshow(X_restored[0].reshape(8, 8), cmap="gray")
axes[1].set_title("压缩后还原图像")
plt.show()

仅保留 20 个主成分,就能恢复接近原始的图像。


第 7 章 深入原理:SVD 与 PCA

PCA 其实可以通过 SVD 来实现。

7.1 SVD 分解

对中心化后的 $X$:

$$ X = U \Sigma V^T $$

其中:

  • $V$ 的列向量就是主成分方向
  • $\Sigma^2$ 对应特征值大小

7.2 Python SVD 实现

U, S, Vt = np.linalg.svd(X - np.mean(X, axis=0))
W = Vt.T[:, :2]
X_pca = (X - np.mean(X, axis=0)) @ W

第 8 章 PCA 的优缺点

优点

  • 降低维度、提高效率
  • 去除噪声
  • 可视化高维数据

缺点

  • 只能捕捉线性关系
  • 主成分缺乏可解释性
  • 需要数据标准化

第 9 章 进阶扩展

  1. Kernel PCA:解决非线性问题
  2. Incremental PCA:适合大规模数据
  3. PCA vs LDA:监督 vs 无监督的降维方法

附录:完整从零实现 PCA 类

class PCAFromScratch:
    def __init__(self, n_components):
        self.n_components = n_components
        self.components = None
        self.mean = None
    
    def fit(self, X):
        # 中心化
        self.mean = np.mean(X, axis=0)
        X_centered = X - self.mean
        
        # 协方差矩阵
        cov_matrix = np.cov(X_centered, rowvar=False)
        
        # 特征值分解
        eig_vals, eig_vecs = np.linalg.eigh(cov_matrix)
        
        # 排序
        sorted_idx = np.argsort(eig_vals)[::-1]
        self.components = eig_vecs[:, sorted_idx][:, :self.n_components]
    
    def transform(self, X):
        X_centered = X - self.mean
        return np.dot(X_centered, self.components)
    
    def fit_transform(self, X):
        self.fit(X)
        return self.transform(X)

总结

本文从 数学推导 → 算法实现 → Python 代码 → 应用案例 → 深入原理 全面剖析了 PCA 算法。

学习要点:

  • PCA 的本质是寻找最大方差方向
  • 可以用 特征值分解SVD 分解 实现
  • 在工程中,常用 sklearn.decomposition.PCA
  • 进阶可研究 Kernel PCA、Incremental PCA

评论已关闭

推荐阅读

AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日
python之plot()和subplot()画图
2024年11月26日
理解 DALL·E 2、Stable Diffusion 和 Midjourney 工作原理
2024年12月01日