当前位置: 首页 > article >正文

【机器学习】手撕封装PCA——将高维数据映射到低维数据的过程

PCA将高维数据映射到低维数据的过程

  • 一、摘要
  • 二、PCA的降维思路
  • 三、PCA代码实现降维过程
    • 3.1 PCA类的实现与封装
    • 3.2 PCA类的使用示例
  • 四、PCA的恢复过程

一、摘要

本文详细介绍了主成分分析法(PCA)在高维数据降维中的应用。首先,阐述了PCA的基本原理,即通过寻找前k个主成分对应的轴的方向,实现从高维数据向低维数据的映射。随后,讲解了如何通过PCA将样本数据从N维映射到k维,包括主成分的计算矩阵乘法降维过程的具体实现。此外,还涉及了PCA的编程实现,包括如何封装PCA为一个类,以及如何通过该类进行数据的降维和恢复。最后,通过实际编程实验展示了PCA降维的基本原理和应用效果,强调了PCA在数据降维中的重要作用。

二、PCA的降维思路

  1. 主成分分析法用于将高维数据映射到低维数据,涉及求取数据集的前n个主成分。

  2. 主成分代表高维空间中的坐标轴方向,通过这些方向可以将数据集从高维空间转换到低维空间。

  3. 样本数据的表示与主成分矩阵

    • 样本数据X表示为m行n列的矩阵,其中m是样本数量,n是特征数量。
      高维数据矩阵 X : X = ( X 1 ( 1 ) X 2 ( 1 ) … X n ( 1 ) X 1 ( 2 ) X 2 ( 2 ) … X n ( 2 ) ⋮ ⋮ ⋱ ⋮ X 1 ( m ) X 2 ( m ) … X n ( m ) ) 高维数据矩阵X:X = \begin{pmatrix} X_1^{(1)} & X_2^{(1)} & \dots & X_n^{(1)} \\ X_1^{(2)} & X_2^{(2)} & \dots & X_n^{(2)} \\ \vdots & \vdots & \ddots & \vdots \\ X_1^{(m)} & X_2^{(m)} & \dots & X_n^{(m)} \end{pmatrix} 高维数据矩阵XX= X1(1)X1(2)X1(m)X2(1)X2(2)X2(m)Xn(1)Xn(2)Xn(m)
      表示 ( m ) 个样本,每个样本有 ( n ) 个特征,维度为 ( m x n )。
      维度为 (m x n)
    • 通过主成分分析法求出的前k个主成分表示为w矩阵,w是一个k行n列的矩阵,代表k个单位方向向量。
      映射矩阵 W k : W k = ( W 1 ( 1 ) W 2 ( 1 ) … W n ( 1 ) W 1 ( 2 ) W 2 ( 2 ) … W n ( 2 ) ⋮ ⋮ ⋱ ⋮ W 1 ( k ) W 2 ( k ) … W n ( k ) ) 映射矩阵W_k:W_k = \begin{pmatrix} W_1^{(1)} & W_2^{(1)} & \dots & W_n^{(1)} \\ W_1^{(2)} & W_2^{(2)} & \dots & W_n^{(2)} \\ \vdots & \vdots & \ddots & \vdots \\ W_1^{(k)} & W_2^{(k)} & \dots & W_n^{(k)} \end{pmatrix} 映射矩阵WkWk= W1(1)W1(2)W1(k)W2(1)W2(2)W2(k)Wn(1)Wn(2)Wn(k)
      维度为 (n x k)
  4. 样本数据的降维映射:矩阵乘法实现降维

    • 公式
      X ⋅ W k T = X k X \cdot W_k^T = X_k XWkT=Xk
    • 维度标注
      • ( X ) 的维度为 ( m x n )
      • (Wk) 的维度为 ( n x k )
      • 运算结果 ( Xk ) 的维度为 ( m x k )
    1. 公式含义
      表示高维数据矩阵 ( X ) 与映射矩阵 ( Wk ) 的转置(( W_k^T ))进行矩阵乘法运算,最终得到低维数据矩阵 ( Xk )。这一过程是高维数据向低维映射的核心计算步骤。换言之,矩阵乘法实现样本数据从N维到k维的映射,通过将x与w的转置相乘完成。x是一个m行n列的矩阵,w是一个k行n列的矩阵,转置后变为n行k列的矩阵。乘法结果得到一个m行k列的矩阵,即降维后的样本数据。

    2. 维度分析

      • ( X ) 是 ( m x n ) 矩阵,代表 ( m ) 个样本,每个样本有 ( n ) 个特征(原始高维数据)。
      • ( Wk ) 是 ( n x k ) 矩阵(( k < n )),用于定义低维空间的映射规则。其转置 Wk维度为 ( k x n )。
      • 根据矩阵乘法规则(前一矩阵的列数与后一矩阵的行数需匹配), X ⋅ W k T X \cdot W_k^T XWkT运算后得到 ( m x k ) 的 ( Xk ),实现了从 ( n ) 维到 ( k ) 维的降维,( Xk ) 即为降维后的低维数据,在保留原始数据主要特征的同时降低了维度。

三、PCA代码实现降维过程

3.1 PCA类的实现与封装

  1. 在PyCharm中新建pythonProject工程并在该工程中加入了pca.py文件,封装了PCA类。

  2. PCA类构造函数传入n_components参数,表示要多少个主成分。

  3. 构造函数中初始化n_components和components变量,components用于存储主成分方向向量。

  4. 具体代码:

    import numpy as np
    
    class PCA:
        def __init__(self,n_components):
            """初始化PCA"""
            assert n_components >= 1, "n_components must be valid."
            self.n_components = n_components
            self.components = None
    
        def fit(self,X,eta=0.01,n_iters=1e4):
            """获得数据集X的前n个主成分"""
            assert self.n_components <= X.shape[1],\
            "n_components must not be greater than the feature number of X."
    
            def demean(X):
                """均值归零"""
                return X - np.mean(X,axis=0)
    
            def f(w,X):
                """目标函数:求w向量,使得目标函数在该方向上的方差最大"""
                return np.sum(X.dot(w) ** 2)/len(X)
    
            def df(w,X):
                """求梯度"""
                return X.T.dot(X.dot(w)) * 2. / len(X)
    
            def direction(w):
                """单位方向向量函数"""
                return w / np.linalg.norm(w)
    
            def first_component(X,initial_w,eta=0.01,n_iters=1e4,epsilon=1e-8):
                """求第一个主成分"""
                w = direction(initial_w)
                cur_iter = 0
                while cur_iter < n_iters:
                    gradient = df(w,X)
                    last_w = w
                    w = w + eta * gradient   # 梯度上升法
                    w = direction(w)
                    if (abs(f(w,X) - f(last_w,X))) < epsilon:
                        break
                    cur_iter += 1
                return w
    
            # 均值归零,将高维矩阵X进行均值归零处理
            X_pca = demean(X)
            # 定义一个空的低维矩阵Wk,也就是映射矩阵,
            self.components_ = np.empty(shape=(self.n_components,X.shape[1]))
            for i in range(self.n_components):
                initial_w = np.random.random(X_pca.shape[1])
                w = first_component(X_pca,initial_w,eta,n_iters)
                self.components_[i,:] = w
    
                X_pca = X_pca - X_pca.dot(w).reshape(-1,1) * w
    
            return self
    
        def transform(self,X):
            """将给定的X,映射到各个主成分分量中"""
            assert X.shape[1] == self.components_.shape[1]
            # 通过矩阵相乘,实现降维:m x n * n x k == m x k 矩阵
            return  X.dot(self.components_.T)
    
        def inverse_transform(self,X):
            """将给定的X,反向映射回元原来的特征空间"""
            assert X.shape[1] == self.components_.shape[0]
            # 通过矩阵相乘,实现维数还原:m x k * k x n == m x n 矩阵
            return X.dot(self.components_)
    
        def __repr__(self):
            return "PCA(n_components=%d)" % self.n_components
    

    在这里插入图片描述

    • 设置fit和transform方法,fit方法用于计算主成分,transform方法用于降维处理。
    • fit方法传入样本数据x和梯度上升法的相关参数,计算前n_components个主成分。
    • transform方法传入样本数据x和已计算出的主成分矩阵,将数据降维到k维。
    • inverse_transform方法用于将低维数据恢复成高维数据。

3.2 PCA类的使用示例

  1. 在notebook中使用封装的PCA类,加载虚拟数据集并进行降维处理。
  2. 实例化PCA类并传入n_components参数,调用fit方法计算主成分。
  3. 调用transform方法将数据降维到k维,调用inverse_transform方法将低维数据恢复成高维数据。
  4. 通过绘制降维前后的数据点,展示PCA降维的效果。
  5. 演示过程:
    • 导入工程
      # 导入在PyCharm中封装好的工程项目
      import sys
      project_path = 'D:/PycharmProjects/pythonProject/'
      if project_path not in sys.path:
          sys.path.append(project_path)
      
    • 具体实现
      from PCA import PCA
      import numpy as np
      import matplotlib.pyplot as plt
      
      X = np.empty((100, 2))
      X[:, 0] = np.random.uniform(0., 100., size=100)
      X[:, 1] = 0.75 * X[:, 0] + 3. + np.random.normal(0, 10., size=100)
      
      # 初始化PCA,传入主成分数量为2个
      pca = PCA(n_components=2)
      
      # 获取X数据集的前2个主成分
      pca.fit(X)
      
      # 查看由2个主成分所构成的矩阵
      pca.components_
      
      # 调用fit_transform函数进行降维操作
      X_reduction = pca.transform(X)
      
      # 查看X_reduction维度
      X_reduction.shape
      
      # 如果期望将数据降到更低维度,比如降到 1 维
      # 那么在初始化 PCA 类时,将 n_components 设置为 1 即可,即 pca = PCA(n_components=1) ,这样再调用 transform 方法后得到的结果维度就会是 (100, 1) 。
      pca = PCA(n_components=1)
      pca.fit(X)
      # 调用fit_transform函数进行降维操作
      X_reduction = pca.transform(X)
      
      # 查看X_reduction维度
      X_reduction.shape
      # PCA恢复
      X_restore = pca.inverse_transform(X_reduction)
      # 查看
      X_restore.shape
      # 绘制图像
      plt.scatter(X[:,0], X[:,1], color='b', alpha=0.5)
      plt.scatter(X_restore[:,0], X_restore[:,1], color='r', alpha=0.5)
      plt.show()
      
      执行过程:
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

四、PCA的恢复过程

  1. 通过将降维后的数据与w矩阵相乘,可以恢复成原始的高维数据。
  2. 恢复过程中会丢失一些信息,但可以从数学上实现低维到高维的映射。
  • 矩阵定义

    • 低维数据矩阵
      X k = ( X 1 ( 1 ) X 2 ( 1 ) … X k ( 1 ) X 1 ( 2 ) X 2 ( 2 ) … X k ( 2 ) … … … … X 1 ( m ) X 2 ( m ) … X k ( m ) ) X_k = \begin{pmatrix} X_1^{(1)} & X_2^{(1)} & \dots & X_k^{(1)} \\ X_1^{(2)} & X_2^{(2)} & \dots & X_k^{(2)} \\ \dots & \dots & \dots & \dots \\ X_1^{(m)} & X_2^{(m)} & \dots & X_k^{(m)} \end{pmatrix} Xk= X1(1)X1(2)X1(m)X2(1)X2(2)X2(m)Xk(1)Xk(2)Xk(m) 维度为 ( m x k )。
    • 映射矩阵 W k = ( W 1 ( 1 ) W 2 ( 1 ) … W n ( 1 ) W 1 ( 2 ) W 2 ( 2 ) … W n ( 2 ) … … … … W 1 ( k ) X 2 ( k ) … X n ( k ) ) W_k = \begin{pmatrix} W_1^{(1)} & W_2^{(1)} & \dots & W_n^{(1)} \\ W_1^{(2)} & W_2^{(2)} & \dots & W_n^{(2)} \\ \dots & \dots & \dots & \dots \\ W_1^{(k)} & X_2^{(k)} & \dots & X_n^{(k)} \end{pmatrix} Wk= W1(1)W1(2)W1(k)W2(1)W2(2)X2(k)Wn(1)Wn(2)Xn(k) 维度为 ( k x n )。
  • 公式 X k ⋅ W k = X m X_k \cdot W_k = X_m XkWk=Xm 维度标注为 m x k、k x n、m x n 。

  • 数据映射逻辑

    • X k X_k Xk 是低维数据矩阵,包含 ( m ) 个样本,每个样本有 ( k ) 个特征,代表高维数据降维后的结果。
    • W k W_k Wk是映射矩阵,用于定义低维空间到高维空间的转换规则。通过矩阵乘法 ( X_k \cdot W_k ),理论上可将低维数据 ( X_k ) 恢复或映射回高维空间,得到 ( m \times n ) 的高维数据 ( X_m )。
  • 矩阵运算意义

    • 从维度看,( X_k )(( m x k ))与 Wk 满足矩阵乘法规则(前一矩阵的列数与后一矩阵的行数均为 ( k )),运算结果 ( Xm ) 的维度为 ( m x n ),即还原出包含 ( n ) 个特征的高维数据。这一过程体现了“低维数据通过映射矩阵重建高维数据”的逆向映射关系,常见于数据降维后的恢复或特征重构场景。

http://www.kler.cn/a/596365.html

相关文章:

  • TPCTF 2025 web 复现
  • 【unordered_set和unordered_map】—— 我与C++的不解之缘(二十七)
  • wyq01
  • geant4的主要模块及其作用:
  • 【大模型算法工程】大模型应用工具化、忠诚度以及知识库场景下PDF双栏解析问题的讨论
  • Apache Flink技术原理深入解析:任务执行流程全景图
  • spring boot 拦截器
  • 【Attention】SKAttention
  • MySQL密码修改的全部方式一篇详解
  • vue学习九
  • 红宝书第十一讲:超易懂版「ES6类与继承」零基础教程:用现实例子+图解实现
  • 生物信息复习笔记(3)——GEO数据库
  • CPU架构和微架构
  • Redis 知识点梳理
  • 如何快速定位高 CPU 使用率的进程
  • git_version_control_proper_practice
  • Linux:基础IO---文件描述符
  • cmakelist中添加opencv
  • 【风信】邮件系统的介绍和使用。
  • Stable Diffusion lora训练(一)