PCA и снижение размерности для Data Scientist
Карьерник — Duolingo для аналитиков: 10 минут в день тренируй SQL, Python, A/B, статистику, метрики и ещё 3 темы собеса. 1500+ вопросов в Telegram-боте. Бесплатно.
Содержание:
Зачем снижать размерность
В табличной задаче 500 признаков. В embeddings — 768 или 1536. В CV-фичах ResNet — 2048. Чем больше размерность, тем хуже:
- Curse of dimensionality — расстояния между точками становятся одинаковыми, классификаторы теряют разрешающую способность
- Шум — большинство признаков содержат больше шума, чем сигнала
- Хранилище и compute — обучение и инференс дорогие
- Визуализация — 768D-вектор человек не видит
Snovenchyaem: PCA для линейного снижения и feature engineering, t-SNE/UMAP для визуализации, autoencoders для нелинейного снижения с обучением.
Главная боль без снижения размерности — кластеризация на 500 фичах даёт «всё похоже на всё», t-SNE на 50k точках без предварительного PCA — час работы.
Математика PCA
Principal Component Analysis — линейное преобразование, которое находит ортогональные оси максимальной дисперсии.
Шаги:
- Центрирование:
X_centered = X - mean(X) - Covariance matrix:
C = X_centered.T @ X_centered / (n - 1) - Eigendecomposition:
C = V Λ V.T, где V — собственные векторы (главные компоненты), Λ — диагональ из собственных значений (дисперсии вдоль компонент) - Сортировка: компоненты по убыванию собственных значений
- Проекция:
X_pca = X_centered @ V[:, :k]— берём k первых компонент
В sklearn:
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
X_scaled = StandardScaler().fit_transform(X)
pca = PCA(n_components=10)
X_pca = pca.fit_transform(X_scaled)
print(pca.explained_variance_ratio_)Технически — PCA через SVD: X_centered = U Σ V.T, главные компоненты = столбцы V, объяснённая дисперсия = Σ² / (n-1). SVD численно стабильнее eigendecomposition.
Объяснённая дисперсия и выбор k
explained_variance_ratio_ — какая доля дисперсии данных объясняется каждой компонентой.
Component 1: 0.45
Component 2: 0.20
Component 3: 0.10
...
Cumulative: 0.45, 0.65, 0.75, 0.83, 0.90, 0.95, ...Правила выбора k:
- Cumulative variance: взять минимальное k, при котором cumsum ≥ 0.90 (или 0.95)
- Elbow rule: график variance vs component, точка перегиба
- Kaiser criterion: оставить компоненты с собственным значением > 1 (для нормированных данных)
- Cross-validation: для downstream-задачи (классификации) подобрать k максимизирующий метрику
import numpy as np
import matplotlib.pyplot as plt
pca = PCA().fit(X_scaled)
cum = np.cumsum(pca.explained_variance_ratio_)
plt.plot(cum)
plt.axhline(0.95, color='red')
k = np.argmax(cum >= 0.95) + 1t-SNE
t-Distributed Stochastic Neighbor Embedding — нелинейное снижение специально для визуализации (обычно в 2D).
Идея:
- В исходном пространстве считаем расстояния → вероятности соседства (Gaussian)
- В целевом 2D — то же, но через t-distribution (тяжёлые хвосты)
- Минимизируем KL-дивергенцию между распределениями
Свойства:
- Сохраняет локальную структуру (соседей)
- Не сохраняет глобальные расстояния (близость кластеров на t-SNE-плоте — артефакт)
- Размер кластеров на t-SNE — артефакт, не интерпретировать
Гиперпараметры:
perplexity— эффективное число соседей (5-50)learning_rate— типично 200, на больших данных —n_samples / 12n_iter— 1000+
from sklearn.manifold import TSNE
X_tsne = TSNE(n_components=2, perplexity=30, learning_rate='auto').fit_transform(X)Минусы:
- Стохастичность: разные runs — разные картинки
- O(n²) — медленный на 50k+ точек
- Не fit/transform — каждый раз пересчёт с нуля
Эвристика: PCA до 50 компонент, потом t-SNE на этих 50.
UMAP
Uniform Manifold Approximation and Projection — нелинейное снижение, конкурент t-SNE.
Преимущества:
- Быстрее t-SNE (O(n^1.14) на практике)
- Лучше сохраняет глобальную структуру (расстояния между кластерами что-то значат)
- Поддерживает
transform()для новых точек - Работает с миллионами точек
Гиперпараметры:
n_neighbors— баланс между local/global (15 — дефолт)min_dist— минимальное расстояние в embedding (0.1 — дефолт)n_components— 2 для виза, можно больше для downstream
import umap
reducer = umap.UMAP(n_components=2, n_neighbors=15, min_dist=0.1)
X_umap = reducer.fit_transform(X)В большинстве задач UMAP — лучший дефолт чем t-SNE.
Когда что выбирать
| Задача | Выбор |
|---|---|
| Линейное снижение для downstream-модели | PCA |
| Удалить мультиколлинеарность | PCA |
| Препроцессинг перед t-SNE | PCA до 50D |
| 2D визуализация структуры | UMAP (или t-SNE) |
| Снижение для нейросети с обучением | Autoencoder |
| Категориальные/смешанные признаки | PCA не лучший выбор; FAMD, MCA, дерева-based importance |
| Sparse матрицы (TF-IDF) | TruncatedSVD (sklearn) |
| Kernel data, нелинейные многообразия | KernelPCA или autoencoders |
Частые ошибки
Не нормировать перед PCA. Признак с большой дисперсией («зарплата в рублях») «съедает» все компоненты. Перед PCA — StandardScaler.
Использовать PCA на категориальных без one-hot. PCA — линейная алгебра над числами. Категорию закодировать (one-hot, target encoding) до PCA.
Интерпретировать t-SNE кластеры как «реальные» расстояния. t-SNE искажает глобальные расстояния. «Кластеры далеко друг от друга» в t-SNE ≠ далеко в исходных данных.
Применять PCA на тесте отдельно. Fit на train, transform на test (через те же главные компоненты). Иначе утечка информации.
Думать, что PCA = feature selection. PCA создаёт новые признаки (комбинации). Selection — выбор из исходных. Если важна интерпретируемость — selection (Lasso, mutual information).
Запускать t-SNE на 100k+ точках без сабсэмпла или PCA-предобработки. Часы работы и плохая структура. Сначала PCA до 50D, потом t-SNE на сабсэмпле или UMAP.
Считать explained_variance_ratio чем-то «всегда сохраняемым». Если данные шумные, 95% дисперсии — это и сигнал, и шум. Variance ≠ информация.
Связанные темы
- Что такое clustering простыми словами
- K-means clustering для аналитика
- Регуляризация L1 и L2 на собесе DS
- Подготовка к собесу Data Scientist
- Hyperparameter tuning на собесе DS
FAQ
PCA или Lasso для отбора признаков?
Lasso удаляет признаки, делает модель из исходных. PCA создаёт новые комбинации, теряет интерпретируемость, но эффективнее устраняет мультиколлинеарность.
Можно ли использовать PCA для классификации напрямую?
PCA не учитывает метки классов — может потерять «полезное» направление с маленькой дисперсией, но различающее классы. Для supervised — LDA (Linear Discriminant Analysis) или просто PCA на маленьком k + классификатор.
t-SNE можно использовать как препроцессинг для классификации?
Не стоит. t-SNE стохастичный, не имеет осмысленного transform для новых данных. Для downstream-задач — PCA или UMAP.
Как PCA работает с пропусками?
Стандартный PCA — никак, нужно заполнить (mean/median/predicted). Для пропусков есть специальные алгоритмы (probabilistic PCA, EM-PCA), реализованы редко.
Какой минимум объяснённой дисперсии оставлять?
90-95% — типично, но зависит от downstream. Если за 95% качество модели падает — оставлять больше. Если задача — визуализация, 2 компоненты независимо от дисперсии.
Это официальная информация?
Нет. Статья основана на классических работах (Pearson 1901 для PCA, van der Maaten-Hinton 2008 для t-SNE, McInnes et al. 2018 для UMAP) и документации sklearn / umap-learn.
Тренируйте Data Science — откройте тренажёр с 1500+ вопросами для собесов.