Машинное обучение — пример визуализации PCA

Представьте, что вы убираете захламлённую комнату, заполненную разными предметами. Чтобы лучше понять планировку комнаты, вы можете сделать несколько фотографий с разных ракурсов (например, спереди, сбоку, сверху).

Анализ главных компонент (PCA)делает нечто подобное в машинном обучении.

PCA — это мощныйинструмент для снижения размерности данныхивизуализации. Когда наши данные содержат сотни или тысячи признаков (измерений), данные находятся как будто в сверхмногомерном пространстве, которое люди не могут интуитивно понять.

PCA помогает нам находить наиболее важные перспективы (т. е. главные компоненты) в данных и проецирует данные на наиболее важные два или три измерения, позволяя нам наблюдать структуру и распределение многомерных данных с помощью двумерных или трёхмерных диаграмм рассеяния.

Проще говоря, цели PCA таковы:

  • Снижение размерности:Использование меньшего числа признаков для представления исходных данных, что уменьшает вычисления и объём хранения, а также удаляет шум.
  • Визуализация:Сведение многомерных данных к 2D или 3D, чтобы можно было интуитивно наблюдать связи между точками данных (например, кластеризацию, разделение).

Основные принципы и рабочий процесс PCA

Основная идея PCA — найти направления, в которых дисперсия данных максимальна.

Чем больше дисперсия, тем сильнее разбросаны спроецированные точки в этом направлении и тем больше информации они содержат.

Первое найденное направление — этопервая главная компонента (PC1),а второе направление, ортогональное PC1 и имеющее следующую по величине дисперсию, — этовторая главная компонента (PC2),и так далее.

Схема рабочего процесса PCA

Ключевые шаги рабочего процесса:

Стандартизация:Сделать так, чтобы каждый признак имел среднее значение 0 и стандартное отклонение 1, обеспечивая всем признакам одинаковую важность при вычислениях.

Ковариационная матрица:Вычислить корреляции между признаками. PCA находит основные направления изменения данных, анализируя эту матрицу.

Собственные значения и собственные векторы:

  • Собственные векторы:Это искомые направления главных компонент.
  • Собственные значения:Они соответствуют дисперсии данных вдоль направления собственного вектора. Чем больше собственное значение, тем важнее соответствующая главная компонента.

Выбор главных компонент:Мы сортируем собственные значения от наибольшего к наименьшему и выбираем собственные векторы, соответствующие K наибольшим собственным значениям. K — это целевая размерность, до которой мы хотим уменьшить данные (например, для визуализации K=2 или 3).

Преобразование данных:Используйте выбранные K собственных векторов, чтобы сформировать матрицу проекции, затем умножьте исходные данные на эту матрицу, чтобы получить координаты в K новых главных компонентах, то есть данные после уменьшения размерности.


Практический пример: визуализация набора данных Iris

Мы будем использовать классическийнабор данных Irisдля демонстрации PCA. Этот набор данных содержит 150 образцов, каждый с 4 признаками (длина чашелистика, ширина чашелистика, длина лепестка, ширина лепестка), и относится к 3 различным видам.

Наша цель — использовать PCA, чтобы уменьшить эти 4-мерные данные до 2 измерений и построить их на 2D-плоскости, чтобы увидеть, можно ли различить разные виды цветов.

Подготовка окружения и загрузка данных

Сначала убедитесь, что у вас установлены необходимые библиотеки Python:scikit-learn, matplotlib, numpy,pandas。

Пример

# Импорт необходимых библиотек
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

# Установить китайский шрифт и стиль графиков (необязательно)
plt.rcParams['font.sans-serif'] = ['SimHei']  # Используется для корректного отображения китайских подписей
plt.rcParams['axes.unicode_minus'] = False  # Используется для правильного отображения отрицательных знаков

# Загрузить набор данных Iris
iris = datasets.load_iris()
X = iris.data  # Данные признаков, форма (150, 4)
y = iris.target  # Целевые метки (виды), форма (150,)
target_names = iris.target_names  # Названия видов: ['setosa', 'versicolor', 'virginica']

print(f"Форма набора данных: {X.shape}")
print(f"Имена признаков: {iris.feature_names}")
print(f"Целевые классы: {target_names}")

Вывод:

数据集形状: (150, 4)
特征名称: ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
目标类别: ['setosa' 'versicolor' 'virginica']

Стандартизация данных

Перед применением PCA стандартизация данных — этоважнейшийшаг.

Поскольку PCA очень чувствителен к масштабу признаков. Если один признак имеет числовой диапазон (например, длина лепестка, измеренная в сантиметрах, значения от 1 до 10) намного больший, чем другой признак (например, ширина чашелистика, измеренная в миллиметрах, значения от 0.1 до 1), то признак с большим диапазоном будет доминировать в направлении главных компонент, что обычно не то, что нам нужно.

Пример

# Стандартизация данных (центрирование и масштабирование до единичной дисперсии)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
print("После стандартизации первые 5 образцов:")
print(X_scaled[:5])

Применение PCA для снижения размерности

Мы используемscikit-learnизPCAкласс PCA, который может легко выполнить все математические вычисления.

Пример

# Создаём объект PCA, указываем сокращение до 2 измерений
pca = PCA(n_components=2)

# Обучаем модель PCA на стандартизированных данных и преобразуем данные
X_pca = pca.fit_transform(X_scaled)

print(f"Форма данных после снижения размерности: {X_pca.shape}")
print(f"Координаты первых 5 образцов на PC1 и PC2:\n{X_pca[:5]}")

# Проверяем долю объяснённой дисперсии каждой главной компоненты
print(f"Доля объяснённой дисперсии главных компонент: {pca.explained_variance_ratio_}")
print(f"Суммарная объяснённая доля дисперсии первых двух главных компонент: {sum(pca.explained_variance_ratio_):.4f}")

Пояснение к коду:

n_components=2: Указывает, что мы хотим уменьшить данные до 2 измерений.

fit_transform(X_scaled): Этот метод выполняет сразу две вещи:

  • fit: На основе входных данных,X_scaledвычислить параметры, необходимые для PCA (например, направления главных компонент).
  • transform: Использовать вычисленные параметры, чтобыX_scaledпреобразовать данные в новое двумерное пространство.

explained_variance_ratio_: Это очень важный атрибут. Он сообщает намдолю дисперсии исходных данных, объясняемую каждой главной компонентой.Например, если вывод равен[0.73, 0.23], это означает, что PC1 сохраняет 73% информации в исходных данных, PC2 сохраняет 23%, а вместе они сохраняют 96% информации. Это помогает нам оценить потерю информации после снижения размерности.

Результаты визуализации

Теперь у нас есть двумерные данныеX_pca, и мы можем легко визуализировать их с помощью диаграммы рассеяния.

Пример

# Создайте диаграмму визуализации
plt.figure(figsize=(8, 6))

# Установите разные цвета и маркеры для каждого вида
colors = ['navy', 'turquoise', 'darkorange']
lw = 2  # Ширина линии

# Пройдите в цикле по трём видам и постройте график для каждого
for color, i, target_name in zip(colors, [0, 1, 2], target_names):
    plt.scatter(X_pca[y == i, 0],  # Выберите координаты PC1 образцов, принадлежащих виду i
                X_pca[y == i, 1],  # Выберите координаты PC2 образцов, принадлежащих виду i
                color=color, alpha=0.8, lw=lw,
                label=target_name)

# Добавьте заголовок диаграммы и подписи осей
plt.title('2D-визуализация PCA набора данных Iris')
plt.xlabel(f'Первая главная компонента (PC1) - доля объяснённой дисперсии: {pca.explained_variance_ratio_)
plt.ylabel(f'Вторая главная компонента (PC2) - доля объяснённой дисперсии: {pca.explained_variance_ratio_)
plt.legend(loc='best', shadow=False, scatterpoints=1)
plt.grid(True, linestyle='--', alpha=0.6)

# Отобразить график
plt.tight_layout()
plt.show()

Интерпретация результатов визуализации:После запуска приведённого выше кода вы получите двумерную диаграмму рассеяния.

  • Ось X (PC1): Представляет направление максимальной дисперсии среди исходных 4 признаков и является наиболее важным измерением для различения данных. Как видно из рисунка, она хорошо отделяет видSetosaот двух других видов.
  • Ось Y (PC2): Представляет направление, ортогональное PC1, со второй по величине дисперсией, и даёт дополнительную различающую информацию. Это помогает дополнительно различитьVersicolorиVirginica (ирис виргинский), хотя они частично перекрываются.
  • Вывод: С помощью PCA мы успешно спроецировали 4-мерные данные на 2D-плоскость и чётко увидели кластеризацию трёх видов. Setosa полностью отделяется, тогда как Versicolor и Virginica частично перекрываются на 2D-проекции, что указывает на то, что использования только первых двух главных компонент (сохраняющих около 95% информации) недостаточно для идеального различения последних двух видов, но основные тенденции их распределения уже очень очевидны.

Дальнейшее исследование и размышления

Как выбрать число главных компонент (значение K)?

В реальных проектах мы можем не знать, до какого числа измерений нужно уменьшить размерность. Распространённый метод — построитьScree Plot, который показывает долю объяснённой дисперсии каждой главной компоненты.

Пример

# Сначала обучим PCA на всех главных компонентах
pca_full = PCA()
pca_full.fit(X_scaled)

# Построим график каменистой осыпи
plt.figure(figsize=(8, 5))
plt.plot(range(1, len(pca_full.explained_variance_ratio_) + 1),
         pca_full.explained_variance_ratio_, 'o-', linewidth=2)
plt.title('График каменистой осыпи доли объяснённой дисперсии PCA')
plt.xlabel('Индекс главной компоненты')
plt.ylabel('Доля объяснённой дисперсии')
plt.grid(True, linestyle='--', alpha=0.6)
plt.xticks(range(1, len(pca_full.explained_variance_ratio_) + 1))
plt.tight_layout()
plt.show()

# Построим график накопленной доли объяснённой дисперсии
plt.figure(figsize=(8, 5))
plt.plot(range(1, len(pca_full.explained_variance_ratio_) + 1),
         np.cumsum(pca_full.explained_variance_ratio_), 's-', linewidth=2, color='red')
plt.title('Накопленная доля объяснённой дисперсии PCA')
plt.xlabel('Число главных компонент')
plt.ylabel('Накопленная доля объяснённой дисперсии')
plt.axhline(y=0.95, color='gray', linestyle='--', label='порог 95%') # Обычный порог
plt.legend()
plt.grid(True, linestyle='--', alpha=0.6)
plt.xticks(range(1, len(pca_full.explained_variance_ratio_) + 1))
plt.tight_layout()
plt.show()

Как выбрать значение K?

  • Посмотрите на точку локтя: На графике каменистой осыпи найдите точку, где снижение доли объяснённой дисперсии внезапно замедляется (то есть локоть). Главные компоненты после неё вносят меньший вклад.
  • Задайте порог: На графике накопленной дисперсии выберите наименьшее значение K, при котором накопленная объяснённая доля достигает удовлетворительного порога (например, 95% или 99%). Из графика накопленной дисперсии для данных iris первые две главные компоненты уже объясняют более 95% дисперсии, поэтому K=2 — хороший выбор.

Понимание смысла главных компонент

Мы также можем посмотреть нанагрузкиглавных компонент, то есть веса вклада каждого исходного признака в главные компоненты, что помогает интерпретировать фактический смысл главных компонент.

Пример

# Получить матрицу нагрузок (собственные векторы) первых двух главных компонент
pca_components = pca.components_  # Форма: (2, 4)

# Используйте DataFrame для более наглядного отображения
df_components = pd.DataFrame(pca_components,
                             columns=iris.feature_names,
                             index=['PC1', 'PC2'])
print("Матрица нагрузок главных компонент (собственные векторы):")
print(df_components)

# Можно визуализировать с помощью тепловой карты
import seaborn as sns
plt.figure(figsize=(8, 4))
sns.heatmap(df_components, annot=True, cmap='RdBu_r', center=0)
plt.title('Тепловая карта нагрузок главных компонент')
plt.tight_layout()
plt.show()

Интерпретация матрицы нагрузок:

  • ДляPC1, если длина и ширина лепестка имеют относительно большиеправильныевеса, тогда как ширина чашелистика имеет относительно большиеотрицательныевеса, тогда PC1 может в основном представлять комплексную особенность контраста между размером лепестка и шириной чашелистика.
  • ДляPC2, картина весов отличается, и она может представлять другую комбинацию признаков. Анализируя эти веса, мы можем придать абстрактным главным компонентам некоторый практический биологический или бизнес-смысл.

Итоги и практические упражнения

Краткое изложение ключевых моментов

  • Что такое PCA: метод линейного снижения размерности без учителя, который заново выражает данные, находя ортогональные направления (главные компоненты) с максимальной дисперсией данных.
  • Основные шаги: стандартизация -> вычисление ковариационной матрицы -> вычисление собственных значений и собственных векторов -> выбор главных компонент -> проецирование данных.
  • Важные понятия:
    • Главные компоненты: новые, некоррелированные оси признаков.
    • Доля объяснённой дисперсии: метрика, которая измеряет важность каждой главной компоненты.
    • Нагрузки: мост, соединяющий исходные признаки и главные компоненты, используемый для объяснения смысла главных компонент.
  • Основные применения: визуализация данных, удаление шума и избыточности, а также использование в качестве этапа предварительной обработки для других моделей (таких как классификация, регрессия) для ускорения обучения.

Практическое занятие

Чтобы закрепить свои знания, попробуйте выполнить следующие упражнения:

Упражнение 1: Изучите различные наборы данныхПопробуйтеscikit-learnв других наборах данных (таких какdigitsнабор данных рукописных цифр илиwineнабор данных wine) для выполнения визуализации PCA. Посмотрите, сохраняют ли изображения после уменьшения размерности различие между разными категориями.

Пример

# Подсказка: загрузите набор данных wine
from sklearn.datasets import load_wine
wine = load_wine()
# ... Повторите процесс PCA

Упражнение 2: 3D-визуализацияСократите данные iris до 3 измерений и используйтеmpl_toolkits.mplot3dбиблиотеку, чтобы нарисовать 3D-диаграмму рассеяния. Посмотрите, уменьшается ли перекрытие между Versicolor и Virginica после добавления одного измерения.

Пример

from mpl_toolkits.mplot3d import Axes3D
pca3 = PCA(n_components=3)
X_pca3 = pca3.fit_transform(X_scaled)
# ... Создать 3D-фигуру для построения графика
Другие расширения