RBFKernelPCA: RBF 核主成分分析

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

> from mlxtend.feature_extraction import RBFKernelPCA

概述

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

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

主成分分析

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

欲了解更多详细信息,请参见关于 mlxtend.feature_extraction.PrincipalComponentAnalysis 的相关文章。

非线性降维

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

核函数和核技巧

处理线性不可分数据的基本思路是将其投影到更高维的空间中,使其变得线性可分。我们将这种非线性映射函数称为 $\phi$,这样一个样本 $\mathbf{x}$ 的映射可以写成 $\mathbf{x} \rightarrow \phi (\mathbf{x})$,这就是所谓的“核函数”。

现在,“核”这个词描述了一个计算样本在 $\phi$ 下映射的图像的点积的函数。

$$\kappa(\mathbf{x_i, x_j}) = \phi (\mathbf{x_i}) \phi (\mathbf{x_j})^T$$

关于这个方程推导的更多细节可以参考Quan Wang的这篇优秀综述文章:核主成分分析及其在面部识别和主动形状模型中的应用。[1]

换句话说,函数 $\phi$ 通过创建原始特征的非线性组合,将原始的 d 维特征映射到一个更大、k 维的特征空间中。例如,如果 $\mathbf{x}$ 由 2 个特征组成:

$$ \mathbf{x} = \big[x_1 \quad x_2\big]^T \quad \quad \mathbf{x} \in I!R^d $$

$$ \Downarrow \phi $$

$$ \mathbf{x}' = \big[x_1 \quad x_2 \quad x_1 x_2 \quad x_{1}^2 \quad x_1 x_{2}^3 \quad \dots \big]^T \quad \quad \mathbf{x} \in I!R^k (k >> d) $$

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

$$ \kappa(\mathbf{x_i, x_j}) = exp\bigg(- \gamma \; \lVert\mathbf{x_i - x_j }\rVert^{2}_{2} \bigg) $$

其中 $\textstyle\gamma = \tfrac{1}{2\sigma^2}$ 是一个需要优化的自由参数。

高斯径向基函数 (RBF) 核主成分分析

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

$$\text{Cov} = \frac{1}{N} \sum_{i=1}^{N} \mathbf{x_i} \mathbf{x_i}^T$$

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

$$\text{Cov} = \frac{1}{N} \sum_{i=1}^{N} \phi(\mathbf{x_i}) \phi(\mathbf{x_i})^T$$

然而,实际上在更高维空间中的协方差矩阵并没有被明确计算(核技巧)。因此,RBF 核主成分分析的实现并不会产生主成分轴(与标准 PCA 相对),但获得的特征向量可以理解为数据在主成分上的投影。

RBF核PCA逐步解析

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

在第一步中,我们需要计算

$$\kappa(\mathbf{x_i, x_j}) = exp\bigg(- \gamma \; \lVert\mathbf{x_i - x_j }\rVert^{2}_{2} \bigg)$$

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

2. 核矩阵的特征分解。

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

$$K' = K - \mathbf{1_N} K - K \mathbf{1_N} + \mathbf{1_N} K \mathbf{1_N}$$

其中 $\mathbf{1_N}$ 是一个 $N\times N$ 的矩阵,所有值都等于 $\frac{1}{N}$。[3]

现在,我们需要获得中心化核矩阵的特征向量,目标是得到最大特征值对应的特征向量。这些特征向量是已经投影到各自主成分上的数据点。

投影新数据

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

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

如果我们想要将一个新的数据点 $\mathbf{x}$ 投影到这个主成分轴上,我们需要计算 $\phi(\mathbf{x})^T \mathbf{g}$。

幸运的是,在这里我们也不需要显式地计算 $\phi(\mathbf{x})^T \mathbf{g}$,而是使用核技巧来计算新数据点与训练数据集中每个数据点 $j$ 之间的 RBF 核:

$$\phi(\mathbf{x})^T \mathbf{g} = \sum_j \alpha_{i} \; \phi(\mathbf{x}) \; \phi(\mathbf{x_j})^T$$

$$= \sum_j \alpha_{i} \; \kappa(\mathbf{x}, \mathbf{x_j})$$

而且核矩阵 $\mathbf{K}$ 的特征向量 $\alpha$ 和特征值 $\lambda$ 满足方程 $\mathbf{K} \alpha = \lambda \alpha$,我们只需通过相应的特征值对特征向量进行归一化。

参考文献

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

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

[3] B. Scholkopf, A. Smola, 和 K.-R. Muller. 作为核特征值问题的非线性成分分析. 神经计算, 10(5):1299–1319, 1998.

示例 1 - 半月形状

我们将从一个简单的例子开始,该例子由scikit-learn中的make_moons函数生成的两个半月形状。

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)将无法为我们提供在一维空间中“良好”的数据表示。让我们使用 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对我们的半月形数据进行降维。$\gamma$的选择取决于数据集,可以通过超参数调优技术如网格搜索来获得。超参数调优本身是一个广泛的话题,这里我只会使用一个我发现能够产生“好”结果的$\gamma$值。

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 Kernel 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中解释的概念,让我们来看另一个经典案例:2个同心圆,外加由scikit-learn的make_circles生成的随机噪声。

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 Kernel Principal Component Analysis for dimensionality reduction.

Parameters

Attributes

Examples

For usage examples, please see https://rasbt.github.io/mlxtend/user_guide/feature_extraction/RBFKernelPCA/

Methods


fit(X)

Learn model from training data.

Parameters

Returns


transform(X)

Apply the non-linear transformation on X.

Parameters

Returns