← Назад к вопросам
Как работает PCA?
1.0 Junior🔥 181 комментариев
#Машинное обучение#Статистика и A/B тестирование
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
PCA (Principal Component Analysis) — один из самых важных методов в машинном обучении для снижения размерности данных. Это линейное преобразование, которое находит новые оси в пространстве признаков, максимизирующие дисперсию данных.
Основная идея PCA
PCA преобразует исходные n признаков в m новых признаков (m < n), сохраняя максимальное количество информации:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_iris
# Загружаем датасет
iris = load_iris()
X = iris.data # 150 samples, 4 features
y = iris.target
print(f"Исходная форма: {X.shape}")
# Шаг 1: Нормализация (КРИТИЧНО!)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# Шаг 2: Применяем PCA
pca = PCA(n_components=2) # Сводим к 2 компонентам
X_pca = pca.fit_transform(X_scaled)
print(f"Форма после PCA: {X_pca.shape}")
# Сколько дисперсии объясняют компоненты?
print(f"\nОбъясненная дисперсия каждой компоненты: {pca.explained_variance_ratio_}")
print(f"Всего объясненной дисперсии: {pca.explained_variance_ratio_.sum():.4f}")
Математика PCA
Шаг 1: Центрирование данных
# Вычитаем среднее (пока данные уже нормализованы)
X_centered = X_scaled - X_scaled.mean(axis=0)
Шаг 2: Вычисление матрицы ковариации
# Матрица ковариации показывает, как изменяются признаки вместе
cov_matrix = np.cov(X_centered.T) # (4, 4) для iris
print(f"Матрица ковариации:\n{cov_matrix}")
print(f"Форма: {cov_matrix.shape}")
Шаг 3: Собственные значения и собственные векторы
PCA находит собственные векторы матрицы ковариации:
# Собственные значения и собственные векторы
eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)
# Сортируем по убыванию собственных значений
idx = eigenvalues.argsort()[::-1]
eigenvalues = eigenvalues[idx]
eigenvectors = eigenvectors[:, idx]
print(f"Собственные значения (дисперсии ПК): {eigenvalues}")
print(f"\nГлавные компоненты (собственные векторы):\n{eigenvectors}")
# Объясненная дисперсия
explained_variance_ratio = eigenvalues / eigenvalues.sum()
print(f"\nОбъясненная дисперсия каждой ПК: {explained_variance_ratio}")
print(f"Кумулятивная: {np.cumsum(explained_variance_ratio)}")
Шаг 4: Проекция на новые оси
# Новые координаты = исходные данные * собственные векторы
X_pca_manual = X_centered @ eigenvectors[:, :2] # Первые 2 компоненты
print(f"Форма после проекции: {X_pca_manual.shape}")
# Сравниваем с scikit-learn
print(f"Совпадают? {np.allclose(X_pca, X_pca_manual)}")
Визуализация PCA
plt.figure(figsize=(12, 5))
# График 1: PCA проекция
plt.subplot(1, 2, 1)
colors = ["red", "green", "blue"]
labels = ["Setosa", "Versicolor", "Virginica"]
for target, color, label in zip([0, 1, 2], colors, labels):
indices = y == target
plt.scatter(X_pca[indices, 0], X_pca[indices, 1],
c=color, label=label, s=50, alpha=0.7)
plt.xlabel(f"PC1 ({pca.explained_variance_ratio_[0]:.2%} дисперсии)")
plt.ylabel(f"PC2 ({pca.explained_variance_ratio_[1]:.2%} дисперсии)")
plt.title("PCA проекция Iris датасета")
plt.legend()
plt.grid(True, alpha=0.3)
# График 2: Cumulative explained variance
plt.subplot(1, 2, 2)
pca_full = PCA()
pca_full.fit(X_scaled)
cumsum = np.cumsum(pca_full.explained_variance_ratio_)
plt.plot(range(1, len(cumsum) + 1), cumsum, "bo-")
plt.axhline(y=0.95, color="r", linestyle="--", label="95% дисперсии")
plt.xlabel("Число компонент")
plt.ylabel("Кумулятивная объясненная дисперсия")
plt.title("Выбор числа компонент")
plt.grid(True, alpha=0.3)
plt.legend()
plt.tight_layout()
plt.show()
Практическое применение
1. Выбор числа компонент
# Метод 1: Удержать 95% дисперсии
pca_95 = PCA(n_components=0.95)
X_pca_95 = pca_95.fit_transform(X_scaled)
print(f"Компонент для 95% дисперсии: {pca_95.n_components_}")
# Метод 2: Локоть (elbow method)
pca_full = PCA()
pca_full.fit(X_scaled)
cumsum = np.cumsum(pca_full.explained_variance_ratio_)
# Находим точку перелома
differences = np.diff(cumsum)
elbw = np.argmax(np.diff(differences)) + 1 # Приблизительно
print(f"\nЛокоть метод предлагает: {elbw + 1} компонент")
# Метод 3: Kaiser rule (собственные значения > 1)
pca_test = PCA()
pca_test.fit(X_scaled)
print(f"Kaiser rule: {(pca_test.explained_variance_ > 1).sum()} компонент")
2. Интерпретация главных компонент
# Какие исходные признаки важны для каждой ПК?
loadings = pca.components_.T * np.sqrt(pca.explained_variance_)
feature_names = iris.feature_names
plt.figure(figsize=(10, 4))
for i in range(2):
plt.subplot(1, 2, i + 1)
plt.barh(feature_names, loadings[:, i])
plt.xlabel(f"Нагрузка (loading) на ПК{i+1}")
plt.title(f"Главная компонента {i+1}")
plt.grid(True, alpha=0.3, axis="x")
plt.tight_layout()
plt.show()
3. Инверсия проекции
# Восстанавливаем исходные данные (с потерей информации)
X_reconstructed = pca.inverse_transform(X_pca)
# Реконструкционная ошибка
reconstruction_error = np.mean((X_scaled - X_reconstructed) ** 2)
print(f"Среднеквадратичная ошибка реконструкции: {reconstruction_error:.4f}")
Когда использовать PCA
Плюсы:
- Снижение размерности → быстрее обучение
- Удаление мультиколлинеарности
- Визуализация высокомерных данных
- Шумоподавление (сохраняем только значимые компоненты)
Минусы:
- Потеря интерпретируемости (новые оси — линейные комбинации)
- Работает только с числовыми признаками
- Предполагает линейные зависимости (для нелинейности есть t-SNE, UMAP)
# Пример: PCA для классификации
from sklearn.pipeline import Pipeline
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
pipeline = Pipeline([
("scaler", StandardScaler()),
("pca", PCA(n_components=0.95)),
("classifier", RandomForestClassifier(random_state=42))
])
scores = cross_val_score(pipeline, X, y, cv=5, scoring="accuracy")
print(f"Accuracy: {scores.mean():.4f} +/- {scores.std():.4f}")
Альтернативы PCA
from sklearn.manifold import TSNE
from sklearn.decomposition import FactorAnalysis
from sklearn.preprocessing import KernelCenterer
from sklearn.decomposition import KernelPCA
# t-SNE для визуализации (нелинейная)
tsne = TSNE(n_components=2, random_state=42)
X_tsne = tsne.fit_transform(X_scaled)
# Kernel PCA для нелинейных данных
kpca = KernelPCA(n_components=2, kernel="rbf", random_state=42)
X_kpca = kpca.fit_transform(X_scaled)
# Factor Analysis (учитывает шум в каждом признаке)
fa = FactorAnalysis(n_components=2, random_state=42)
X_fa = fa.fit_transform(X_scaled)
Ключевые выводы
- PCA находит новые оси, максимизирующие дисперсию
- Работает через собственные значения и вектора матрицы ковариации
- ВСЕГДА нормализуйте данные перед PCA
- Выбирайте компоненты через 95% дисперсии или Kaiser rule
- PCA линейна — для нелинейности используйте t-SNE или UMAP
- Теряется интерпретируемость — главные компоненты это комбинации исходных признаков
PCA — базовый навык Data Scientist'а, особенно полезен для работы с высокомерными данными.