RBFKernelPCA: RBF 核主成分分析

用于非线性降维的 RBF 核主成分分析实现

from mlxtend.feature_extraction import RBFKernelPCA

概述

大多数机器学习算法是为线性可分数据开发并经过统计验证的。常见的例子包括支持向量机 (SVM) 等线性分类器或用于降维的(标准)主成分分析 (PCA)。然而,大多数实际世界数据需要非线性方法才能成功执行涉及模式分析和发现的任务。

本概述的重点是简要介绍核方法的思想,并实现一个高斯径向基函数 (RBF) 核,该核用于通过 RBF 核主成分分析 (kPCA) 执行非线性降维。

主成分分析

主成分分析 (PCA) 的主要目的是分析数据,以识别能够“很好”地代表数据的模式。主成分可以理解为数据集的新轴,它们最大化沿这些轴的方差(即协方差矩阵的特征向量)。换句话说,PCA 的目标是找到数据分布最广且方差最大的轴。

有关更多详细信息,请参阅有关 mlxtend.feature_extraction.PrincipalComponentAnalysis 的相关文章。

非线性降维

上面描述的“经典”PCA 方法是一种线性投影技术,如果数据是线性可分的,则效果很好。然而,对于线性不可分的数据,如果任务是降低数据集的维度,则需要一种非线性技术。

核函数和核技巧

处理线性不可分数据的基本思想是将其投影到更高维度的空间,使其变得线性可分。我们称这个非线性映射函数为以便样本的映射可以写成,这被称为“核函数”。

现在,“核”一词描述了一个函数,该函数计算样本图像的内积在...下.

有关此方程推导的更多详细信息,请参阅 Quan Wang 的这篇优秀综述文章:核主成分分析及其在人脸识别和主动形状模型中的应用。[1]

换句话说,函数通过创建原始特征的非线性组合,将原始 d 维特征映射到更大的 k 维特征空间。例如,如果包含 2 个特征

通常,RBF 核的数学定义写成并实现为

其中是一个自由参数,需要优化。

高斯径向基函数 (RBF) 核 PCA

在线性 PCA 方法中,我们关注最大化数据集方差的主成分。这通过提取与基于协方差矩阵的最大特征值对应的主成分(特征向量)来完成。

Bernhard Scholkopf (核主成分分析 [2]) 将此方法推广到通过核函数映射到更高维空间的数据

然而,在实践中,高维空间中的协方差矩阵不会被显式计算(核技巧)。因此,RBF 核 PCA 的实现不会得到主成分轴(与标准 PCA 不同),但获得的特征向量可以理解为数据在主成分上的投影。

RBF 核 PCA 分步讲解

1. 计算核(相似性)矩阵。

第一步,我们需要计算

对于每一对点。例如,如果我们有一个包含 100 个样本的数据集,这一步将得到一个对称的 100x100 核矩阵。

2. 对核矩阵进行特征分解。

由于核矩阵不一定是以中心化的,我们可以应用以下公式进行中心化:

其中是一个(像核矩阵一样)所有元素都等于 的矩阵. [3]

现在,我们必须获取中心化核矩阵中对应于最大特征值的特征向量。这些特征向量就是已经投影到相应主成分上的数据点。

投影新数据

到目前为止,一切顺利。在上面的章节中,我们已经将一个数据集投影到一个新的特征子空间。然而,在实际应用中,我们通常对将新的数据点映射到同一个新的特征子空间感兴趣(例如,如果在模式分类任务中使用训练集和测试集)。

请记住,当我们计算特征向量时中心化核矩阵的这些值实际上已经是投影到主成分轴上的数据点.

如果我们要将新的数据点投影到这个主成分轴上,我们需要计算.

幸运的是,在这里,我们也不必计算显式地,而是使用核技巧计算新数据点与训练集中的每个数据点之间的 RBF 核在训练数据集中

以及特征向量和特征值核矩阵的满足方程,我们只需要用相应的特征值对特征向量进行归一化。

参考文献

[1] Q. Wang. 核主成分分析及其在人脸识别和主动形状模型中的应用。CoRR, abs/1207.3538, 2012。

[2] B. Scholkopf, A. Smola, and K.-R. Muller. 核主成分分析。页码 583–588, 1997。

[3] B. Scholkopf, A. Smola, and K.-R. Muller. 作为核特征值问题的非线性分量分析。Neural computation, 10(5):1299–1319, 1998。

示例 1 - 半月形数据

我们将从一个简单示例开始,使用 scikit-learn 的 make_moons 函数生成 2 个半月形数据。

import matplotlib.pyplot as plt
from sklearn.datasets import make_moons

X, y = make_moons(n_samples=50, random_state=1)

plt.scatter(X[y==0, 0], X[y==0, 1], 
            color='red', marker='o', alpha=0.5)
plt.scatter(X[y==1, 0], X[y==1, 1], 
            color='blue', marker='^', alpha=0.5)
plt.ylabel('y coordinate')
plt.xlabel('x coordinate')

plt.show()

png

由于这两个半月形数据是线性不可分的,我们预计“经典”PCA 无法在 1D 空间中为我们提供数据的“良好”表示。让我们使用 PCA 类进行降维。

from mlxtend.feature_extraction import PrincipalComponentAnalysis as PCA

pca = PCA(n_components=2)
X_pca = pca.fit(X).transform(X)

plt.scatter(X_pca[y==0, 0], X_pca[y==0, 1], 
            color='red', marker='o', alpha=0.5)
plt.scatter(X_pca[y==1, 0], X_pca[y==1, 1], 
            color='blue', marker='^', alpha=0.5)

plt.xlabel('PC1')
plt.ylabel('PC2')
plt.show()

png

正如我们所见,结果主成分没有产生一个能够很好地线性分离数据的子空间。注意,PCA 是一种无监督方法,与线性判别分析不同,它不“考虑”类别标签来最大化方差。在这里,蓝色和红色仅用于可视化目的,以指示分离程度。

接下来,我们将对半月形数据通过 RBF 核 PCA 执行降维。的选择取决于数据集,可以通过网格搜索等超参数调优技术获得。超参数调优本身是一个很大的主题,这里我将仅使用一个值,该值被我发现可以产生“良好”的结果。

from mlxtend.data import iris_data
from mlxtend.preprocessing import standardize
from mlxtend.feature_extraction import RBFKernelPCA as KPCA

kpca = KPCA(gamma=15.0, n_components=2)
kpca.fit(X)
X_kpca = kpca.X_projected_

请注意,RBF 核 PCA 等核方法的成分已经代表了投影后的数据点(与 PCA 不同,PCA 中成分轴是用于构建投影矩阵的“前 k 个”特征向量,然后用该投影矩阵转换训练样本)。因此,投影后的训练集在拟合后通过 .X_projected_ 属性可用。

plt.scatter(X_kpca[y==0, 0], X_kpca[y==0, 1], 
            color='red', marker='o', alpha=0.5)
plt.scatter(X_kpca[y==1, 0], X_kpca[y==1, 1], 
            color='blue', marker='^', alpha=0.5)

plt.title('First 2 principal components after RBF Kernel PCA')
plt.xlabel('PC1')
plt.ylabel('PC2')
plt.show()

png

新的特征空间现在是线性可分的。由于我们通常对降维感兴趣,我们只看看第一个成分。

import numpy as np

plt.scatter(X_kpca[y==0, 0], np.zeros((25, 1)), 
            color='red', marker='o', alpha=0.5)
plt.scatter(X_kpca[y==1, 0], np.zeros((25, 1)), 
            color='blue', marker='^', alpha=0.5)

plt.title('First principal component after RBF Kernel PCA')
plt.xlabel('PC1')
plt.yticks([])
plt.show()

png

我们可以清楚地看到,通过 RBF 核 PCA 的投影产生了一个类别分离良好的子空间。这样的子空间可以作为广义线性分类模型(例如逻辑回归)的输入。

投影新数据

最后,通过 transform 方法,我们可以将新数据投影到新的成分轴上。

import matplotlib.pyplot as plt
from sklearn.datasets import make_moons

X2, y2 = make_moons(n_samples=200, random_state=5)
X2_kpca = kpca.transform(X2)

plt.scatter(X_kpca[y==0, 0], X_kpca[y==0, 1], 
            color='red', marker='o', alpha=0.5, label='fit data')
plt.scatter(X_kpca[y==1, 0], X_kpca[y==1, 1], 
            color='blue', marker='^', alpha=0.5, label='fit data')

plt.scatter(X2_kpca[y2==0, 0], X2_kpca[y2==0, 1], 
            color='orange', marker='v', 
            alpha=0.2, label='new data')
plt.scatter(X2_kpca[y2==1, 0], X2_kpca[y2==1, 1], 
            color='cyan', marker='s', 
            alpha=0.2, label='new data')

plt.legend()
plt.show()

png

示例 2 - 同心圆

遵循示例 1 中解释的概念,我们来看看另一个经典案例:由 scikit-learn 的 make_circles 生成的 2 个带随机噪声的同心圆。

from sklearn.datasets import make_circles

X, y = make_circles(n_samples=1000, random_state=123, 
                    noise=0.1, factor=0.2)

plt.figure(figsize=(8,6))

plt.scatter(X[y==0, 0], X[y==0, 1], color='red', alpha=0.5)
plt.scatter(X[y==1, 0], X[y==1, 1], color='blue', alpha=0.5)
plt.title('Concentric circles')
plt.ylabel('y coordinate')
plt.xlabel('x coordinate')
plt.show()

png

from mlxtend.data import iris_data
from mlxtend.preprocessing import standardize
from mlxtend.feature_extraction import RBFKernelPCA as KPCA

kpca = KPCA(gamma=15.0, n_components=2)
kpca.fit(X)
X_kpca = kpca.X_projected_
plt.scatter(X_kpca[y==0, 0], X_kpca[y==0, 1], 
            color='red', marker='o', alpha=0.5)
plt.scatter(X_kpca[y==1, 0], X_kpca[y==1, 1], 
            color='blue', marker='^', alpha=0.5)

plt.title('First 2 principal components after RBF Kernel PCA')
plt.xlabel('PC1')
plt.ylabel('PC2')
plt.show()

png

plt.scatter(X_kpca[y==0, 0], np.zeros((500, 1)), 
            color='red', marker='o', alpha=0.5)
plt.scatter(X_kpca[y==1, 0], np.zeros((500, 1)), 
            color='blue', marker='^', alpha=0.5)

plt.title('First principal component after RBF Kernel PCA')
plt.xlabel('PC1')
plt.yticks([])
plt.show()

png

API

RBFKernelPCA(gamma=15.0, n_components=None, copy_X=True)

用于降维的 RBF 核主成分分析。

参数

  • gamma : 浮点数 (默认值: 15.0)

    RBF 核的自由参数(系数)。

  • n_components : 整数 (默认值: None)

    用于转换的主成分数量。如果为 None,则保留数据集的原始维度。

  • copy_X : 布尔值 (默认值: True)

    复制训练数据,这是通过 transform 方法计算新数据投影所必需的。如果为 False,则使用对 X 的引用。

属性

  • e_vals_ : 类似数组, 形状=[n_features]

    按排序顺序排列的特征值。

  • e_vecs_ : 类似数组, 形状=[n_features]

    按排序顺序排列的特征向量。

  • X_projected_ : 类似数组, 形状=[n_samples, n_components]

    沿成分轴投影的训练样本。

示例

用法示例请参阅 https://mlxtend.cn/mlxtend/user_guide/feature_extraction/RBFKernelPCA/

方法


fit(X)

从训练数据学习模型。

参数

  • X : {类似数组, 稀疏矩阵}, 形状 = [n_samples, n_features]

    训练向量,其中 n_samples 是样本数,n_features 是特征数。

返回值

  • self : 对象

transform(X)

对 X 应用非线性变换。

参数

  • X : {类似数组, 稀疏矩阵}, 形状 = [n_samples, n_features]

    训练向量,其中 n_samples 是样本数,n_features 是特征数。

返回值

  • X_projected : np.ndarray, 形状 = [n_samples, n_components]

    投影后的训练向量。