Примечание
Перейти в конец, чтобы загрузить полный пример кода. или запустить этот пример в браузере через JupyterLite или Binder
Ядерный PCA
В этом примере показано различие между методом анализа главных компонент (Principal Components Analysis, PCA) и его ядерной версией (KernelPCA).
С одной стороны, мы показываем, что KernelPCA способен найти проекцию данных, которая линейно их разделяет, в то время как для PCA это не так.
Наконец, мы показываем, что обращение этой проекции является приближением с использованием KernelPCA, в то время как с PCA это точное преобразование.
# Authors: The scikit-learn developers # SPDX-License-Identifier: BSD-3-Clause
Проектирование данных: PCA против KernelPCA
В этом разделе мы показываем преимущества использования ядра при проектировании данных с использованием анализа главных компонент (PCA). Мы создаем набор данных, состоящий из двух вложенных окружностей.
from sklearn.datasets import make_circles from sklearn.model_selection import train_test_split X, y = make_circles(n_samples=1_000, factor=0.3, noise=0.05, random_state=0) X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=0)
Давайте кратко рассмотрим сгенерированный набор данных.
import matplotlib.pyplot as plt
_, (train_ax, test_ax) = plt.subplots(ncols=2, sharex=True, sharey=True, figsize=(8, 4))
train_ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train)
train_ax.set_ylabel("Feature #1")
train_ax.set_xlabel("Feature #0")
train_ax.set_title("Training data")
test_ax.scatter(X_test[:, 0], X_test[:, 1], c=y_test)
test_ax.set_xlabel("Feature #0")
_ = test_ax.set_title("Testing data")

Образцы из каждого класса не могут быть линейно разделены: нет прямой линии, которая может разделить образцы внутреннего множества от внешнего множества.
Теперь мы воспользуемся PCA с ядром и без ядра, чтобы увидеть, какой эффект оказывает использование такого ядра. Здесь используется радиальная базисная функция (RBF).
from sklearn.decomposition import PCA, KernelPCA
pca = PCA(n_components=2)
kernel_pca = KernelPCA(
n_components=None, kernel="rbf", gamma=10, fit_inverse_transform=True, alpha=0.1
)
X_test_pca = pca.fit(X_train).transform(X_test)
X_test_kernel_pca = kernel_pca.fit(X_train).transform(X_test)
fig, (orig_data_ax, pca_proj_ax, kernel_pca_proj_ax) = plt.subplots(
ncols=3, figsize=(14, 4)
)
orig_data_ax.scatter(X_test[:, 0], X_test[:, 1], c=y_test)
orig_data_ax.set_ylabel("Feature #1")
orig_data_ax.set_xlabel("Feature #0")
orig_data_ax.set_title("Testing data")
pca_proj_ax.scatter(X_test_pca[:, 0], X_test_pca[:, 1], c=y_test)
pca_proj_ax.set_ylabel("Principal component #1")
pca_proj_ax.set_xlabel("Principal component #0")
pca_proj_ax.set_title("Projection of testing data\n using PCA")
kernel_pca_proj_ax.scatter(X_test_kernel_pca[:, 0], X_test_kernel_pca[:, 1], c=y_test)
kernel_pca_proj_ax.set_ylabel("Principal component #1")
kernel_pca_proj_ax.set_xlabel("Principal component #0")
_ = kernel_pca_proj_ax.set_title("Projection of testing data\n using KernelPCA")

Напомним, что PCA преобразует данные линейно. Интуитивно это означает, что система координат будет центрирована, масштабирована по каждому компоненту относительно его дисперсии и, наконец, повернута. Полученные данные после преобразования будут изотропными и могут быть спроецированы на свои главные компоненты.
Таким образом, если посмотреть на проекцию, выполненную с помощью PCA (т.е. средняя фигура), мы видим, что масштабирование не изменилось; действительно, поскольку данные представляют собой две концентрические окружности, центрированные в нуле, исходные данные уже изотропны. Однако мы можем видеть, что данные были повернуты. В заключение, мы видим, что такая проекция не поможет, если определить линейный классификатор для различения образцов обоих классов.
Использование ядра позволяет выполнить нелинейную проекцию. Здесь, используя RBF-ядро, мы ожидаем, что проекция развернет набор данных, сохраняя при этом примерно сохраняя относительные расстояния пар точек данных, которые близки друг к другу в исходном пространстве.
Мы наблюдаем такое поведение на рисунке справа: образцы данного класса находятся ближе друг к другу, чем образцы противоположного класса, разделяя оба набора образцов. Теперь мы можем использовать линейный классификатор для разделения образцов из двух классов.
Проекция в исходное пространство признаков
Одна особенность, которую следует учитывать при использовании KernelPCA, связана с восстановлением (т.е. обратной проекцией в исходное пространство признаков). С помощью PCA восстановление будет точным, если n_components равно числу исходных признаков. В этом примере это так.
Мы можем проверить, получим ли мы исходный набор данных при обратной проекции с KernelPCA.
X_reconstructed_pca = pca.inverse_transform(pca.transform(X_test)) X_reconstructed_kernel_pca = kernel_pca.inverse_transform(kernel_pca.transform(X_test))
fig, (orig_data_ax, pca_back_proj_ax, kernel_pca_back_proj_ax) = plt.subplots(
ncols=3, sharex=True, sharey=True, figsize=(13, 4)
)
orig_data_ax.scatter(X_test[:, 0], X_test[:, 1], c=y_test)
orig_data_ax.set_ylabel("Feature #1")
orig_data_ax.set_xlabel("Feature #0")
orig_data_ax.set_title("Original test data")
pca_back_proj_ax.scatter(X_reconstructed_pca[:, 0], X_reconstructed_pca[:, 1], c=y_test)
pca_back_proj_ax.set_xlabel("Feature #0")
pca_back_proj_ax.set_title("Reconstruction via PCA")
kernel_pca_back_proj_ax.scatter(
X_reconstructed_kernel_pca[:, 0], X_reconstructed_kernel_pca[:, 1], c=y_test
)
kernel_pca_back_proj_ax.set_xlabel("Feature #0")
_ = kernel_pca_back_proj_ax.set_title("Reconstruction via KernelPCA")

В то время как мы видим идеальное восстановление с помощью PCA, для KernelPCA результат будет другим.
Действительно, inverse_transform не может полагаться на аналитическую обратную проекцию и, следовательно, точное восстановление. Вместо этого, внутренне обучается KernelRidge для обучения отображению из базиса ядерного PCA в исходное пространство признаков. Этот метод, следовательно, сопровождается приближением, вносящим небольшие различия при обратной проекции в исходное пространство признаков.
Для улучшения восстановления с помощью inverse_transform, можно настроить alpha в KernelPCA, член регуляризации, который контролирует зависимость от обучающих данных во время обучения отображения.
Общее время выполнения скрипта: (0 минут 0,563 секунды)
Связанные примеры
© 2007–2025 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.6/auto_examples/decomposition/plot_kernel_pca.html