哈喽,我是Johngo~
今天有一位读者拿到了小米职能部的offer。
有一个有趣的事情分享过来,就是在一系列的面试环节中,都非常的顺畅。维度,问到了核PCA,居然想不到一些核心的逻辑,回答的惨不忍睹。
在其他的环节中,还是不错的,最终还是一个非常好的结果。
今天这里也和大家聊聊「核PCA」~
每天分享干货,记得关注~
核主成分分析(Kernel Principal Component Analysis,简称核PCA)是一种基于核方法的非线性降维技术。它通过将数据映射到高维特征空间来捕捉数据的非线性结构,而传统的PCA是在线性空间中进行降维的。核PCA的核心思想是通过核技巧避免显式地进行特征空间的高维映射,只在低维空间中计算内积,从而减少计算的复杂性。
下面,咱们通过详细的推理和案例好好和大家聊聊~
1. 核PCA的基本思路
传统的PCA通过求解数据的协方差矩阵,并选择其特征值最大的特征向量来进行降维。核PCA则是将这种降维方法推广到非线性情况下。它的核心思想是通过非线性映射(使用核函数)将数据从低维空间映射到高维特征空间,在这个特征空间中进行PCA降维。
核PCA的步骤如下:
选择核函数:选择合适的核函数 来计算数据点之间的相似度。 中心化数据:数据需要在高维特征空间中进行中心化处理,这一步是核PCA的关键。 计算核矩阵:构建核矩阵 ,它是数据点之间的内积矩阵。 计算特征值和特征向量:对中心化后的核矩阵进行特征值分解,得到主成分。 选择主成分:选择前 个最大的特征值对应的特征向量,进行降维。
2. 核PCA的数学推导
假设我们有一个数据集 ,其中每个 。传统PCA的目标是通过线性变换找到一个正交基,使得数据在这些基上的方差最大。
非线性映射
我们首先考虑将数据映射到一个更高维的特征空间 ,通过一个非线性映射 将每个样本 映射到特征空间中:
在高维特征空间中,我们可以计算数据点之间的内积:
其中 是核函数。常见的核函数有:
线性核: 高斯核: 多项式核:
通过核函数,我们可以计算高维特征空间中的内积而不需要显式地计算 。
数据中心化
PCA的一个关键步骤是数据中心化,意味着数据的均值应为零。为了在高维空间中进行类似的操作,我们需要对核矩阵进行中心化。
定义核矩阵 ,其元素为 。接着,我们对 进行中心化:
其中, 是一个全为 1 的 列向量。
特征分解
接下来,我们对中心化后的核矩阵 进行特征值分解:
其中, 是特征值, 是对应的特征向量。通过特征值分解,我们可以得到各个主成分。
降维
选择前 个最大的特征值对应的特征向量 ,作为新的基进行降维。
降维后的数据表示为:
这样,数据就从原来的低维空间降到了新的 -维空间。
核PCA 实践案例
1. 问题背景
在高维数据中,传统的PCA方法常常受限于数据的线性性质。核PCA提供了一个有效的非线性降维方法,通过使用核函数将数据映射到更高维的特征空间,在高维空间中进行PCA降维。我们将使用虚拟数据集,使用高斯核(Gaussian Kernel)进行映射,展示核PCA的效果。
2. 核PCA的目标
我们将使用核PCA方法:
生成一个二维的虚拟数据集,其中数据具有非线性的分布。 应用核PCA对数据进行降维处理。 通过图形展示降维前后的数据分布。
3. 核PCA Python实现
数据生成
我们首先生成一个二维的非线性数据集,可以通过组合正弦和余弦函数生成一个复杂的数据集。数据点会呈现出复杂的曲线分布,适合展示核PCA的优势。
核PCA的实现
我们将使用scikit-learn
库中的PCA功能,但结合核技巧来实现核PCA。核函数的选择将使用高斯核(RBF核)。然后,我们将使用matplotlib
和seaborn
进行数据可视化。
代码实现
代码包含数据生成、模型训练以及图形绘制。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_moons
from sklearn.preprocessing import StandardScaler
from sklearn.metrics.pairwise import rbf_kernel
# 核PCA实现
class KernelPCA:
def __init__(self, kernel="rbf", gamma=1.0):
self.kernel = kernel
self.gamma = gamma
self.alpha_ = None
self.eigenvalues_ = None
self.eigenvectors_ = None
self.X_centered_ = None
self.K_ = None
def fit(self, X):
# 计算核矩阵
if self.kernel == "rbf":
K = rbf_kernel(X, X, gamma=self.gamma)
else:
raise ValueError("Unsupported kernel")
# 数据中心化:K' = K - 1 * K - K * 1 + 1 * K * 1
n_samples = X.shape[0]
one_n = np.ones((n_samples, n_samples)) / n_samples
K_centered = K - one_n.dot(K) - K.dot(one_n) + one_n.dot(K).dot(one_n)
# 特征值分解
eigenvalues, eigenvectors = np.linalg.eigh(K_centered)
# 排序特征值和特征向量
sorted_indices = np.argsort(eigenvalues)[::-1]
self.eigenvalues_ = eigenvalues[sorted_indices]
self.eigenvectors_ = eigenvectors[:, sorted_indices]
# 保存中心化后的核矩阵
self.K_ = K_centered
def transform(self, X):
# 重新计算核矩阵
K = rbf_kernel(X, X, gamma=self.gamma)
# 数据中心化
n_samples = X.shape[0]
one_n = np.ones((n_samples, n_samples)) / n_samples
K_centered = K - one_n.dot(K) - K.dot(one_n) + one_n.dot(K).dot(one_n)
# 投影到特征空间
return np.dot(K_centered, self.eigenvectors_)
# 数据生成:通过make_moons生成一个非线性数据集
X, y = make_moons(n_samples=3000, noise=0.1, random_state=42)
# 标准化数据
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 核PCA降维
kpca = KernelPCA(kernel="rbf", gamma=1.0)
kpca.fit(X_scaled)
X_kpca = kpca.transform(X_scaled)
# 绘制原始数据和降维后的数据
fig, axs = plt.subplots(1, 2, figsize=(14, 6))
# 绘制原始数据
axs[0].scatter(X[:, 0], X[:, 1], c=y, cmap="coolwarm", edgecolor='k', s=80)
axs[0].set_title("Original Data (Moons)")
axs[0].set_xlabel("Feature 1")
axs[0].set_ylabel("Feature 2")
# 绘制核PCA降维后的数据
axs[1].scatter(X_kpca[:, 0], X_kpca[:, 1], c=y, cmap="coolwarm", edgecolor='k', s=80)
axs[1].set_title("Data After KernelPCA")
axs[1].set_xlabel("PC 1")
axs[1].set_ylabel("PC 2")
plt.tight_layout()
plt.show()
KernelPCA类:我们自定义了一个类
KernelPCA
,用于实现核PCA。类初始化时选择核函数(默认为RBF核)以及核函数的参数gamma
。然后在fit
方法中计算核矩阵,并进行中心化和特征值分解。transform
方法用于将数据映射到降维后的空间。数据生成:我们使用
make_moons
函数生成一个具有噪声的双月型数据集。该数据集具有明显的非线性分布,适合展示核PCA的优势。数据标准化:在应用核PCA之前,我们对数据进行了标准化,确保每个特征的均值为0,方差为1。
降维与可视化:
我们将数据投影到核PCA的前两个主成分,并绘制原始数据与降维后的数据对比。 使用 matplotlib
进行可视化,左图为原始数据,右图为降维后的数据。通过不同的颜色展示数据点的类别。
左图:原始的双月型数据。数据点分布呈现出非线性的特点。
右图:降维后的数据。通过核PCA,数据成功映射到一个新的特征空间,并且非线性关系在二维空间中得到了很好的展现。
6. 进一步的分析
通过核PCA降维后的数据,可以进一步分析数据的分布情况,观察如何通过非线性映射捕获数据的内部结构。例如,我们可以通过增加降维后的主成分数量,来查看数据在更高维空间中的表现。
降维到更高维空间
我们可以尝试将数据降到三个主成分,并绘制三维图形。
# 使用核PCA将数据降到三维
X_kpca_3d = kpca.transform(X_scaled)
# 3D绘图
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
# 绘制降维后的数据
scatter = ax.scatter(X_kpca_3d[:, 0], X_kpca_3d[:, 1], X_kpca_3d[:, 2], c=y, cmap='coolwarm', s=80)
ax.set_title("3D Projection After KernelPCA")
ax.set_xlabel("PC 1")
ax.set_ylabel("PC 2")
ax.set_zlabel("PC 3")
# 添加色条
fig.colorbar(scatter)
plt.show()
运行后,将会展示降维后的三维数据分布,使我们能够更好地理解核PCA在捕捉数据结构中的作用。
通过核PCA,我们成功地将复杂的非线性数据集降到二维空间,并能通过视觉化展示出数据的内在结构。非线性的数据关系在降维后的空间中变得更加可分,展示了核PCA的强大非线性映射能力。
核PCA是一种强大的非线性降维工具,能够捕捉传统PCA无法捕捉的数据结构。通过核函数将数据映射到高维空间,再通过特征分解进行降维,核PCA能够有效地在复杂的数据集中找到潜在的低维结构。通过可视化,我们能够清晰地看到降维前后数据的变化,展现了核PCA在处理非线性数据时的优势。
最后,给大家一个限时福利,超值 1 元,手慢无~