Лабораторная работа №14: Снижение размерности (PCA и t-SNE)
Цель: Научиться бороться с проклятием размерности. Мы сожмем изображения рукописных цифр из 64 измерений в 2 измерения для визуализации, определим оптимальное количество компонент для сохранения информации и сравним эффективность линейного (PCA) и нелинейного (t-SNE) подходов.
Инструменты:
sklearn.decomposition: PCA.sklearn.manifold: t-SNE.sklearn.preprocessing: StandardScaler.time: для замера скорости обучения моделей.
Данные: Digits Dataset (из sklearn). Картинки 8x8 пикселей.
- Исходная размерность: 64 признака (пикселя).
- Количество классов: 10 (цифры 0-9).
Часть 1: Подготовка и Стандартизация
Важность масштабирования
PCA работает, вращая оси координат. Если данные не отмасштабированы, ось с самым большим разбросом значений (например, центральный пиксель) перетянет всё внимание на себя.
Задание 1.1: Загрузка и Scaling
- Загрузите
load_digits. - Примените
StandardScalerк матрице признаковX.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_digits
from sklearn.preprocessing import StandardScaler
# Загрузка
digits = load_digits()
X = digits.data
y = digits.target
print(f"Исходная форма данных: {X.shape}") # (1797, 64)
# TODO: Примените StandardScaler
# scaler = ...
# X_scaled = ...
Часть 2: PCA для визуализации (2D)
Мы не можем представить 64-мерное пространство. Но мы можем сжать его до 2D и нарисовать.
Часть 3: Выбор оптимального числа компонент
Сколько измерений нужно оставить, чтобы сохранить 90% информации о цифре?
Задание 3.1: График кумулятивной дисперсии
- Обучите PCA на всех компонентах (по умолчанию
n_components=Noneилиmin(n_samples, n_features)). - Постройте график кумулятивной суммы (
np.cumsum) объясненной дисперсии. - Найдите количество компонент, необходимое для 90% дисперсии.
# TODO: PCA на всех компонентах
# pca_full = PCA(random_state=42)
# pca_full.fit(X_scaled)
# TODO: Кумулятивная сумма
# cumsum = np.cumsum(pca_full.explained_variance_ratio_)
# График
# plt.figure(figsize=(10, 6))
# plt.plot(cumsum, marker='o', linestyle='--')
# plt.axhline(y=0.90, color='r', linestyle='-')
# plt.text(0, 0.92, '90% Threshold', color = 'red', fontsize=12)
# plt.xlabel('Количество компонент')
# plt.ylabel('Сохраненная дисперсия')
# plt.grid()
# plt.show()
# TODO: Программно найдите индекс, где сумма > 0.90 (np.argmax поможет)
# n_90 = ...
# print(f"Нужно {n_90} компонент, чтобы сохранить 90% информации.")
Часть 4: PCA как ускоритель ML
Инженеры используют PCA не только для картинок, но и для ускорения тяжелых моделей. Если у вас 10 000 признаков, модель будет учиться вечность. Если сжать их до 500, качество почти не упадет, а скорость вырастет в разы.
Задание 4.1: Сравнение скорости
- Обучите
LogisticRegressionна исходных данных (X_scaled). Замерьте время. - Обучите ту же модель на сжатых данных (количество компонент возьмите из задания 3.1, например 20-30). Замерьте время.
- Сравните Accuracy.
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import time
# Разделение (на оригинальных данных)
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.3, random_state=42)
# PCA трансформация
# pca_90 = PCA(n_components=n_90) # Используйте n_90 из прошлого шага (или поставьте 0.90 в n_components)
# X_train_pca = pca_90.fit_transform(X_train)
# X_test_pca = pca_90.transform(X_test)
# --- 1. Обучение на сырых данных ---
start = time.time()
# logit = LogisticRegression(max_iter=1000)
# logit.fit(X_train, y_train)
raw_time = time.time() - start
# raw_acc = accuracy_score(y_test, logit.predict(X_test))
# --- 2. Обучение на PCA данных ---
start = time.time()
# logit_pca = LogisticRegression(max_iter=1000)
# logit_pca.fit(X_train_pca, y_train)
pca_time = time.time() - start
# pca_acc = accuracy_score(y_test, logit_pca.predict(X_test_pca))
# print(f"Raw Data: {raw_time:.4f} sec, Accuracy: {raw_acc:.4f}")
# print(f"PCA Data: {pca_time:.4f} sec, Accuracy: {pca_acc:.4f}")
Вывод по производительности
На маленьком датасете Digits выигрыш во времени может быть небольшим, но на реальной Big Data разница колоссальная.
Часть 5: t-SNE (Визуализация многообразий)
PCA сжимает “блинчиком”. t-SNE пытается распутать “клубок ниток”. Это гораздо более мощный инструмент для визуализации кластеров.
Задание 5.1: t-SNE проекция
Долгие вычисления
Внимание: t-SNE работает долго. На этом датасете займет 10-30 секунд.
- Импортируйте
TSNE. - Примените его к
X_scaled. - Постройте Scatter plot.
from sklearn.manifold import TSNE
# TODO: Запустите t-SNE (n_components=2)
# tsne = TSNE(n_components=2, random_state=42, perplexity=30, n_iter=1000)
# X_tsne = tsne.fit_transform(X_scaled)
# Визуализация
# plt.figure(figsize=(10, 8))
# sns.scatterplot(x=X_tsne[:, 0], y=X_tsne[:, 1], hue=y, palette='tab10', legend='full')
# plt.title("t-SNE Projection")
# plt.show()
Сравнение: Посмотрите, насколько лучше t-SNE разделил классы по сравнению с PCA из Части 2. Группы цифр должны быть отчетливо видны и отделены друг от друга.