字节算法专家,Kernel PCA分析太强了。。。

文摘   2024-09-12 18:12   北京  

你好,我是kk~

字节的算法专家,今天和我们在聊了一些算法的核心思想。

趁着这个机会,咱们今天把Kernel PCA分享给大家。

核主成分分析(Kernel Principal Component Analysis, Kernel PCA) 是主成分分析(PCA)的非线性扩展,利用核技巧将数据从原始空间映射到高维特征空间,在该特征空间中进行线性PCA以捕获数据的非线性特征。核PCA非常适合处理非线性的数据结构。

核PCA核心思想

PCA的核心在于通过线性变换寻找数据分布的主轴。然而,PCA是一种线性方法,如果数据在原空间中的分布是非线性的,PCA的效果就不理想。核PCA通过核技巧(Kernel Trick)来解决这个问题,它将数据映射到高维空间,在高维空间中找到数据的线性结构,从而捕获原始数据的非线性结构。

具体步骤如下:

1. 数据映射到高维空间:通过非线性映射函数 ,将输入数据  从原空间映射到高维空间。

2. 在高维空间进行PCA:计算映射后数据的协方差矩阵,并进行特征值分解,找到特征向量和特征值。

3. 利用核函数避免显式映射:通过核函数  来直接计算点积,从而避免直接计算高维特征空间中的映射 


核PCA数学推导

假设我们有  个数据点 ,目标是找到主成分并降维。PCA通过以下步骤实现:

1. 中心化数据:对数据进行均值中心化处理:

2. 计算协方差矩阵

3. 求协方差矩阵的特征值和特征向量:通过对协方差矩阵  进行特征值分解,找到对应的特征向量作为主成分方向。

核PCA的高维映射

现在我们考虑核PCA。假设有一个非线性映射函数 ,将输入数据从原空间映射到高维空间:

其中  是一个高维甚至无限维的特征空间。

目标:在这个高维空间中做PCA。我们需要计算映射后数据的协方差矩阵,并进行特征值分解。

1. 中心化数据:数据映射后,我们首先对数据进行均值中心化:

2. 协方差矩阵:在高维空间中,协方差矩阵为:

我们的目标是对这个协方差矩阵进行特征值分解,找到特征值和特征向量。

核技巧(Kernel Trick)

由于  是高维甚至无限维的空间,显式计算  的点积会非常昂贵。核技巧允许我们通过核函数  来直接计算特征空间中点积 ,避免显式映射。

核函数  定义为:

常用的核函数包括:

  • 线性核:$
  • 多项式核:$
  • 高斯RBF核:$

特征值分解

由于核技巧,我们实际上只需要处理核矩阵 ,其中:

此时我们需要对核矩阵  进行特征值分解。

设核矩阵的特征值分解为:

其中  是特征向量矩阵, 是特征值矩阵。

在PCA中,我们希望在高维空间中找到主成分的方向,即特征向量 ,满足:

结合核技巧和特征值分解的结果,特征向量  可以表示为数据在高维空间的线性组合:

通过将这一表达式代入到特征方程中,并利用核矩阵的性质,可以推导出以下结果:

其中  是特征向量的系数向量。


核PCA的具体步骤

总结核PCA的步骤如下:

**1. 构建核矩阵 **:

  • 计算核矩阵 
  • 对核矩阵进行中心化:令  为全为    矩阵,有:

2. 特征值分解

  • 对中心化后的核矩阵  进行特征值分解,得到特征值和特征向量。

3. 选择主成分

  • 根据特征值的大小选择前  个最大的特征值对应的特征向量。
  • 核PCA降维后的新表示为:

其中  是特征值分解得到的特征向量的分量。

核PCA的本质是通过核技巧将原始数据映射到一个高维特征空间,在该空间中进行线性PCA以捕捉数据的非线性结构。通过利用核函数避免了直接计算高维空间中的点积,从而使得计算变得更加高效。核PCA的推导建立在特征空间中的PCA基础上,通过核函数  和特征值分解来获得主成分方向和降维后的数据表示。

案例

大致步骤:

1. 生成虚拟数据:我们将生成一些具有复杂非线性分布的数据集,以展示标准线性PCA的局限性,以及核PCA如何帮助我们捕捉非线性特征。

2. 应用核主成分分析:使用Python的sklearn库进行核PCA,并展示如何将数据投影到低维空间。

3. 生成复杂且鲜艳的图形:绘制多个图形,包括原始数据、PCA和核PCA降维后的数据分布,分析结果。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA, KernelPCA
from sklearn.datasets import make_moons, make_circles
from sklearn.preprocessing import StandardScaler


# 生成两个非线性数据集:半月形和同心圆数据集
def generate_datasets():
    # 半月形数据集
    X_moons, y_moons = make_moons(n_samples=2000, noise=0.1, random_state=42)

    # 同心圆数据集
    X_circles, y_circles = make_circles(n_samples=1000, noise=0.05, factor=0.4, random_state=42)

    return (X_moons, y_moons), (X_circles, y_circles)


# 标准化数据
def standardize_data(X):
    scaler = StandardScaler()
    return scaler.fit_transform(X)


# 绘制原始数据集
def plot_original_data(X_moons, y_moons, X_circles, y_circles):
    fig, (ax1, ax2) = plt.subplots(12, figsize=(146))

    # 绘制半月形数据集
    ax1.scatter(X_moons[y_moons == 0][:, 0], X_moons[y_moons == 0][:, 1], color='red', s=30, label='Class 0')
    ax1.scatter(X_moons[y_moons == 1][:, 0], X_moons[y_moons == 1][:, 1], color='blue', s=30, label='Class 1')
    ax1.set_title('Original Moons Dataset', fontsize=15)
    ax1.legend()
    ax1.grid(True)

    # 绘制同心圆数据集
    ax2.scatter(X_circles[y_circles == 0][:, 0], X_circles[y_circles == 0][:, 1], color='green', s=30, label='Class 0')
    ax2.scatter(X_circles[y_circles == 1][:, 0], X_circles[y_circles == 1][:, 1], color='purple', s=30, label='Class 1')
    ax2.set_title('Original Circles Dataset', fontsize=15)
    ax2.legend()
    ax2.grid(True)

    plt.show()


# PCA和Kernel PCA降维后的数据可视化
def plot_pca_kpca(X_moons, y_moons, X_circles, y_circles):
    # 标准化数据
    X_moons_std = standardize_data(X_moons)
    X_circles_std = standardize_data(X_circles)

    # 定义PCA和Kernel PCA
    pca = PCA(n_components=2)
    kpca_rbf = KernelPCA(n_components=2, kernel='rbf', gamma=15)
    kpca_poly = KernelPCA(n_components=2, kernel='poly', degree=3, gamma=1, coef0=1)

    # 计算PCA降维结果
    X_moons_pca = pca.fit_transform(X_moons_std)
    X_circles_pca = pca.fit_transform(X_circles_std)

    # 计算核PCA降维结果 (RBF核和多项式核)
    X_moons_kpca_rbf = kpca_rbf.fit_transform(X_moons_std)
    X_moons_kpca_poly = kpca_poly.fit_transform(X_moons_std)

    X_circles_kpca_rbf = kpca_rbf.fit_transform(X_circles_std)
    X_circles_kpca_poly = kpca_poly.fit_transform(X_circles_std)

    # 绘制PCA和Kernel PCA降维的可视化结果
    fig, axes = plt.subplots(32, figsize=(1418))

    # 半月形数据集PCA
    axes[00].scatter(X_moons_pca[y_moons == 0][:, 0], X_moons_pca[y_moons == 0][:, 1], color='red', s=30,
                       label='Class 0')
    axes[00].scatter(X_moons_pca[y_moons == 1][:, 0], X_moons_pca[y_moons == 1][:, 1], color='blue', s=30,
                       label='Class 1')
    axes[00].set_title('Moons PCA', fontsize=15)
    axes[00].legend()
    axes[00].grid(True)

    # 同心圆数据集PCA
    axes[01].scatter(X_circles_pca[y_circles == 0][:, 0], X_circles_pca[y_circles == 0][:, 1], color='green', s=30,
                       label='Class 0')
    axes[01].scatter(X_circles_pca[y_circles == 1][:, 0], X_circles_pca[y_circles == 1][:, 1], color='purple', s=30,
                       label='Class 1')
    axes[01].set_title('Circles PCA', fontsize=15)
    axes[01].legend()
    axes[01].grid(True)

    # 半月形数据集RBF核PCA
    axes[10].scatter(X_moons_kpca_rbf[y_moons == 0][:, 0], X_moons_kpca_rbf[y_moons == 0][:, 1], color='red', s=30,
                       label='Class 0')
    axes[10].scatter(X_moons_kpca_rbf[y_moons == 1][:, 0], X_moons_kpca_rbf[y_moons == 1][:, 1], color='blue', s=30,
                       label='Class 1')
    axes[10].set_title('Moons Kernel PCA (RBF)', fontsize=15)
    axes[10].legend()
    axes[10].grid(True)

    # 同心圆数据集RBF核PCA
    axes[11].scatter(X_circles_kpca_rbf[y_circles == 0][:, 0], X_circles_kpca_rbf[y_circles == 0][:, 1],
                       color='green', s=30, label='Class 0')
    axes[11].scatter(X_circles_kpca_rbf[y_circles == 1][:, 0], X_circles_kpca_rbf[y_circles == 1][:, 1],
                       color='purple', s=30, label='Class 1')
    axes[11].set_title('Circles Kernel PCA (RBF)', fontsize=15)
    axes[11].legend()
    axes[11].grid(True)

    # 半月形数据集多项式核PCA
    axes[20].scatter(X_moons_kpca_poly[y_moons == 0][:, 0], X_moons_kpca_poly[y_moons == 0][:, 1], color='red', s=30,
                       label='Class 0')
    axes[20].scatter(X_moons_kpca_poly[y_moons == 1][:, 0], X_moons_kpca_poly[y_moons == 1][:, 1], color='blue', s=30,
                       label='Class 1')
    axes[20].set_title('Moons Kernel PCA (Polynomial)', fontsize=15)
    axes[20].legend()
    axes[20].grid(True)

    # 同心圆数据集多项式核PCA
    axes[21].scatter(X_circles_kpca_poly[y_circles == 0][:, 0], X_circles_kpca_poly[y_circles == 0][:, 1],
                       color='green', s=30, label='Class 0')
    axes[21].scatter(X_circles_kpca_poly[y_circles == 1][:, 0], X_circles_kpca_poly[y_circles == 1][:, 1], color='purple',
               s=30, label='Class 1')
    axes[21].set_title('Circles Kernel PCA (Polynomial)', fontsize=15)
    axes[21].legend()
    axes[21].grid(True)

plt.show()


# 主函数
def main():
    # 生成数据
    (X_moons, y_moons), (X_circles, y_circles) = generate_datasets()

    # 绘制原始数据
    plot_original_data(X_moons, y_moons, X_circles, y_circles)

    # 应用PCA和Kernel PCA并绘图
    plot_pca_kpca(X_moons, y_moons, X_circles, y_circles)


if __name__ == "__main__":
    main()

1. 数据生成:使用make_moonsmake_circles函数生成两组具有非线性分布的数据,分别是半月形数据集和同心圆数据集。

2. 数据标准化:我们使用StandardScaler对数据进行标准化处理,以确保不同维度的数据具有相同的尺度,这对于PCA和核PCA是重要的预处理步骤。

3. PCA和核PCA降维:我们分别应用PCA和两种不同的核PCA(RBF核和多项式核)来对数据进行降维。RBF核是一种常用的核函数,能够捕捉复杂的非线性模式,而多项式核可以帮助我们探索多项式特征之间的关系。

  • 原始数据的可视化:绘制了半月形和同心圆数据集的原始二维表示。
  • PCA降维结果:展示了标准PCA在非线性数据上的效果,通常无法很好地分离数据。

核PCA降维结果:通过RBF和多项式核PCA,我们能够更好地捕捉数据的非线性特征,并在低维空间中将类进行更好的分离。

通过整个的理论和案例,大家清楚地看到核PCA的强大之处。与标准PCA不同,核PCA可以通过非线性映射,捕捉复杂的非线性特征,特别适合非线性分布的数据集。

kk机器学习算法
机器学习基础、计算机视觉…
 最新文章