24/11/7 算法笔记 PCA主成分分析

news/2024/11/8 12:54:25 标签: 算法, 笔记, 信息可视化

假如我们的数据集是n维的,共有m个数据(x^{(1)},x^{(2)},...,x^{(m)})。我们希望将这m个数据的维度从n维降到k维,希望这m个k维的数据集尽可能的代表原始数据集。我们知道数据从n维降到k维肯定会有损失,但是我们希望损失尽可能的小。那么如何让这k维的数据尽可能表示原来的数据呢?

        我们先看看最简单的情况,也就是n=2,K=1,也就是将数据从二维降维到一维。数据如下图。我们希望找到某一个维度方向,它可以代表这两个维度的数据。图中列了两个向量方向,u1和u2,那么哪个向量可以更好的代表原始数据集呢?从直观上也可以看出,u1比u2好。

可以有两种解释,第一种解释是样本点到这个直线的距离足够近,第二种解释是样本点在这个直线上的投影能尽可能的分开。

        假如我们把K从1维推广到任意维,我们希望降维的标准为:样本点到这个超平面的距离足够近,或者说样本点在这个超平面上的投影能尽可能的分开。

PCA(主成分分析)是一种统计技术,它通过正交变换将一组可能相关的变量转换为一组线性不相关的变量,称为主成分。这些主成分按照方差的大小排序,第一个主成分具有最大的方差,第二个主成分具有第二大的方差,依此类推。以下是PCA的工作原理和关键步骤:

1. 标准化数据

由于PCA对数据的尺度敏感,因此在进行PCA之前,通常需要对数据进行标准化处理,使得每个特征的均值为0,标准差为1。这一步是必要的,因为PCA依赖于协方差矩阵,而协方差矩阵会因特征的尺度差异而产生偏差。

2. 计算协方差矩阵

在数据标准化之后,计算数据的协方差矩阵。协方差矩阵是一个方阵,其元素表示不同特征之间的协方差。对于数据集 XX(假设已经中心化),协方差矩阵 ΣΣ 定义为:

其中 n 是样本数量。

3. 计算协方差矩阵的特征值和特征向量

协方差矩阵的特征值和特征向量可以提供关于数据结构的重要信息。特征值表示每个特征的方向上的数据方差量,而特征向量表示这些特征的方向。

4. 选择主成分

根据特征值的大小,选择最大的 k 个特征值对应的特征向量。这些特征向量代表了数据中最重要的 k 个主成分。特征值的大小表示了每个主成分的重要性或方差贡献。

5. 构造新的特征空间

使用选定的特征向量作为新特征空间的基,将原始数据投影到这个新的特征空间上。这个过程实际上是将原始数据集转换为一个新的数据集,其中每个数据点由 k 个主成分的线性组合表示。

6. 解释结果

新数据集中的每个维度(即每个主成分)都代表了原始数据集中的某种结构或模式。通常,第一个主成分捕获了数据中最大的方差,第二个主成分捕获了第二大的方差,且与第一个主成分正交。

PCA的应用

  • 降维:通过减少数据的维度来简化数据集,同时保留最重要的信息。
  • 数据可视化:将高维数据投影到二维或三维空间,以便可视化。
  • 去噪:通过去除小的特征值对应的成分来减少数据中的噪声。
  • 特征提取:在机器学习中,PCA可以作为预处理步骤,提取更有意义的特征。

下面是他的代码:

import numpy as np
from scipy.linalg import svd

class PCA:
    def __init__(self, n_components=None, whiten=False, copy=True):
        self.n_components = n_components
        self.whiten = whiten
        self.copy = copy

    def fit(self, X, y=None):
        X = np.asarray(X)
        if X.ndim == 1:
            X = X[:, np.newaxis]
        
        # Center the data
        self.mean_ = np.mean(X, axis=0)
        X = X - self.mean_

        # Perform SVD
        U, S, V = svd(X, full_matrices=False)
        if self.n_components is None:
            self.n_components_ = V.shape[1]
        else:
            self.n_components_ = min(self.n_components, V.shape[1])

        # Store the components
        self.components_ = V[:self.n_components_]

        # Store the explained variance
        self.explained_variance_ = S[:self.n_components_]**2 / X.shape[0]
        
        return self

    def transform(self, X):
        check_is_fitted(self)
        X = np.asarray(X)
        if X.shape[1] != self.mean_.shape[0]:
            raise ValueError("Shape of X is different from the shape used to fit the model")
        
        X = X - self.mean_
        return np.dot(X, self.components_.T)

    def fit_transform(self, X, y=None, **kwargs):
        self.fit(X)
        return self.transform(X)

    def inverse_transform(self, X):
        check_is_fitted(self)
        X = np.asarray(X)
        return np.dot(X, self.components_) + self.mean_

    def score_samples(self, X):
        X = self.transform(X)
        return np.sum(X**2, axis=1)

    def score(self, X, y=None):
        # This method is not implemented in this simplified version
        pass

# Helper function to check if the model is fitted
def check_is_fitted(model):
    if not hasattr(model, 'components_'):
        raise ValueError("Model is not fitted")


# Example usage
from sklearn.datasets import load_iris
iris = load_iris()
X = iris.data
pca = PCA(n_components=2)
X_r = pca.fit_transform(X)
print(X_r.shape)  # Output: (150, 2)

1. 导入依赖

import numpy as np
from scipy.linalg import svd

svd用于执行奇异值分解,我有讲过。

2. PCA 类定义

class PCA:
    def __init__(self, n_components=None, whiten=False, copy=True):
        self.n_components = n_components
        self.whiten = whiten
        self.copy = copy

这是 PCA 类的构造函数,它初始化了几个重要的属性:

  • n_components:要保留的主成分数量。如果设置为 None,则保留所有成分。
  • whiten:是否进行白化处理,即是否将主成分的方差缩放到1。
  • copy:是否在处理数据时复制数据,以避免修改原始数据。

3. 拟合方法

def fit(self, X, y=None):
    X = np.asarray(X)
    if X.ndim == 1:
        X = X[:, np.newaxis]
        
    # Center the data
    self.mean_ = np.mean(X, axis=0)
    X = X - self.mean_

    # Perform SVD
    U, S, V = svd(X, full_matrices=False)
    if self.n_components is None:
        self.n_components_ = V.shape[1]
    else:
        self.n_components_ = min(self.n_components, V.shape[1])

    # Store the components
    self.components_ = V[:self.n_components_]

    # Store the explained variance
    self.explained_variance_ = S[:self.n_components_]**2 / X.shape[0]
        
    return self

fit 方法用于计算数据的PCA变换:

  • 首先,将数据转换为 numpy 数组,并确保数据是二维的。
  • 计算数据的均值,并中心化数据(减去均值)。
  • 执行SVD,得到 US 和 V 三个矩阵。
  • SVD可以看之前的文章24/11/6 算法笔记 SVD-CSDN博客
  • 根据 n_components 的设置,确定保留的主成分数量。
  • 保存主成分(V 矩阵的列)和解释的方差。

主成分有什么用:

  • PCA可以减少数据的维度,同时保留最重要的特征。这有助于去除噪声和冗余信息,使得数据集更易于管理和分析。

4. 转换方法

def transform(self, X):
    check_is_fitted(self)
    X = np.asarray(X)
    if X.shape[1] != self.mean_.shape[0]:
        raise ValueError("Shape of X is different from the shape used to fit the model")
        
    X = X - self.mean_
    return np.dot(X, self.components_.T)

transform 方法用于将新数据投影到主成分上:

  • 确保模型已经被拟合。
  • 将输入数据转换为 numpy 数组,并检查数据的形状是否与拟合时的数据一致。
  • 中心化数据。
  • 将数据与主成分的转置矩阵相乘,得到降维后的数据。

5. 拟合和转换方法

def fit_transform(self, X, y=None, **kwargs):
    self.fit(X)
    return self.transform(X)

fit_transform 方法结合了 fittransform 方法,先拟合模型,然后将数据投影到主成分上。

6. 逆变换方法

def inverse_transform(self, X):
    check_is_fitted(self)
    X = np.asarray(X)
    return np.dot(X, self.components_) + self.mean_

7.样本得分函数

def score_samples(self, X):
    X = self.transform(X)
    return np.sum(X**2, axis=1)

8.辅助函数

def check_is_fitted(model):
    if not hasattr(model, 'components_'):
        raise ValueError("Model is not fitted")

http://www.niftyadmin.cn/n/5743925.html

相关文章

北斗智能定位平板终端|三防平板|北斗有源终端|北斗搜救终端

在当今快速发展的科技时代,智能设备的应用已经渗透到我们生活的方方面面,从日常娱乐到专业工作,无一不彰显着科技的魅力。特别是在高精度定位领域,随着全球卫星导航系统(GNSS)技术的不断进步,智…

海外云手机在出海业务中的优势有哪些?

随着互联网技术的快速发展,海外云手机已在出海电商、海外媒体推广和游戏行业都拥有广泛的应用。对于国内的出海电商企业来说,短视频引流和社交平台推广是带来有效流量的重要手段。借助云手机,企业能够更高效地在新兴社交平台上推广产品和品牌…

Xserver v1.4.2发布,支持自动重载 nginx 配置

Xserver——优雅、强大的 php 集成开发环境 本次更新为大家带来了更好的用户体验。 🎉 下载依赖组件时,显示进度条,展示下载进度。 🎉 保存站点信息和手动修改 vhost 配置文件之后,自动重载 nginx 配置 &#x1f41e…

【杂谈】-Linux系统编程涉及的一些相关概念

Linux系统编程涉及的一些相关概念 文章目录 Linux系统编程涉及的一些相关概念1、什么是系统编程2、系统调用2.1 调用系统调用2.2 C库2.3 C编译器 3、应用程序编程接口(APIs)和应用程序二进制接口(ABIs)3.1 应用程序编程接口3.2 应…

记录学习react的一些内容

由于是在公司实际项目中学习&#xff0c;所以不是很完整 需要一点一点的学 1.React.useState 类似于vue中的ref 可以修改状态 但是是异步的 感觉不好用 const [wishData, setWishData] React.useState<any>(null); 只能使用setxxx来修改 2.useEffect(()>{},[]) 类…

萤石设备视频接入平台EasyCVR多品牌摄像机视频平台海康ehome平台(ISUP)接入EasyCVR不在线如何排查?

随着智慧城市和数字化转型的推进&#xff0c;视频监控系统已成为保障公共安全、提升管理效率的重要工具。特别是在大中型项目中&#xff0c;跨区域的网络化视频监控需求日益增长&#xff0c;这要求视频监控管理平台不仅要具备强大的视频资源管理能力&#xff0c;还要能够适应多…

AndroidStudio 加载grade失败问题解决

1:在gradle-wrapper.properties中添加国内镜像 distributionUrlhttp\://mtl-gradle-mirror.oss-cn-hangzhou.aliyuncs.com/gradle-5.6.4-bin.zip 2&#xff1a;在build.gradle中加上阿里镜像 repositories {maven { url https://maven.aliyun.com/repository/public/ }maven …

C/C++使用AddressSanitizer检测内存错误

AddressSanitizer 是一种内存错误检测工具&#xff0c;编译时添加 -fsanitizeaddress 选项可以在运行时检测出非法内存访问&#xff0c;当发生段错误时&#xff0c;AddressSanitizer 会输出详细的错误报告&#xff0c;包括出错位置的代码行号和调用栈&#xff0c;有助于快速定位…