Использование PCA для уменьшения размерности и визуализации шаблонов в Python

Анализ главных компонентов, сокращенно PCA, - это метод обучения без учителя, используемый для выявления основных закономерностей в данных.

В этой статье мы рассмотрим, как PCA работает с реальным примером агента по недвижимости, который хочет понять, почему закрытие некоторых из их списков занимает слишком много времени, и как мы можем использовать PCA для кодирования меньшего набора данных. .

Ваша подруга Мэгги - агент по недвижимости, и она недоумевает, почему некоторые объекты недвижимости, которыми управляет ее компания, не были проданы более шести месяцев. Она знает, что вы специалист по анализу данных, и спрашивает, не могли бы вы помочь ей разобраться в происходящем.

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

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

Но найти закономерности в большом наборе данных с множеством атрибутов, обычно называемых функциями, вручную невозможно.

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

Например, вы заметили, что в наборе данных Мэгги есть функции для:

  • Общее количество дверей в доме,
  • Общее количество спален,
  • Общее количество санузлов.

Наличие функции для общего количества дверей не похоже на то, чтобы раскрыть что-то важное в данных, поскольку у нас есть две другие функции. С точки зрения статистики, общее количество дверей в доме, скорее всего, является избыточной характеристикой и не объясняет расхождения в данных.

Хорошо, ничего страшного! Если общее количество дверей в доме избыточно, мы можем удалить его из набора данных. В нашем случае это имеет смысл, но в наборе данных с сотнями или даже тысячами функций нам нужно быть более осторожными.

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

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

Чтобы найти закономерности в этом наборе данных, вы сразу же думаете об Анализе главных компонентов.

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

В то время как в контролируемых методах обучения мы должны иметь метку для каждого наблюдения, поскольку цель состоит в том, чтобы предсказать класс или число, в неконтролируемом обучении цель состоит в том, чтобы искать закономерности в данных.

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

Как работает PCA

Цель анализа главных компонентов - применить к данным линейные преобразования, чтобы минимизировать шум и избыточность. Результатом является набор данных, который раскрывает наиболее важные характеристики данных.

После применения PCA у вас будет набор основных компонентов, ранжированных в порядке убывания их вклада в описание закономерностей в данных. Выражаясь статистическим языком, они ранжируются в зависимости от того, какую вариативность они объясняют.

Первый главный компонент является наиболее важным при описании дисперсии данных. Остальные основные компоненты менее критичны, так как они отражают изменчивость закономерностей в данных.

За кулисами Анализ главных компонентов использует статистические инструменты для выявления шума и избыточности в наборе данных. Он использует ковариационную матрицу для анализа:

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

Ковариационная матрица выделяет то, что мешает выявлению закономерностей в данных. Итак, в конце концов, какая PCA создаст набор основных компонентов, которые:

  • Уменьшите шум, максимизируя вариативность функций.
  • Уменьшите избыточность, сведя к минимуму ковариацию между парами функций.

В основе PCA лежит ковариационная матрица, и на практике существует два подхода к идентификации основных компонентов:

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

На этапе исследовательского анализа мы также хотели бы создать парную диаграмму и выявить любые четкие корреляции между функциями. Но даже в этом небольшом фиктивном наборе данных всего с 17 функциями результирующий парный график огромен и медленен для вычисления. Это имеет смысл, поскольку нам нужно построить 17 графиков, и выберите 2 = 136 отдельных участков.

Нормализация и масштабирование функций

Первым шагом в PCA является нормализация данных и обеспечение нормального распределения всех функций. Затем данные будут следовать стандартному нормальному распределению со средним значением, равным нулю, и стандартным отклонением, равным единице.

Нормализация данных преобразует каждую функцию в общее представление и делает сопоставимыми все значения функций. Особенно важно нормализовать объекты, если они имеют разный масштаб. Например, когда одна функция указана в милях, а другая - в минутах.

Нормализация также гарантирует, что основными компонентами являются:

  • Линейно независимый. Каждый главный компонент представляет собой линейную комбинацию, которая не состоит из других основных компонентов.
  • Ортогональный. Это означает, что все основные компоненты находятся под углом 90 градусов друг к другу.

Есть несколько способов нормализовать ваши функции, обычно называемые масштабированием функций. Одним из них является нормализация Z-баллов, также называемая стандартизацией.

Чтобы применить нормализацию Z-оценки к набору данных, вы обновляете значение каждой точки данных таким образом, чтобы:

Мы пошли в обход, чтобы поговорить о нормализации, но большинство статистических библиотек сделают это за вас. С библиотеками Python, такими как ScikitLearn или statsmodels, вам просто нужно установить несколько параметров.

В конце процесса PCA закодирует ваши функции в основные компоненты. Но важно отметить, что основные компоненты не обязательно однозначно соотносятся с функциями. Они представляют собой новое представление набора данных и могут кодировать сразу несколько функций.

Взглянем на ковариационную матрицу

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

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

  • На недиагонали - пары избыточных функций. Подтверждая нашу первоначальную догадку, спальни и number_doors имеют ковариацию 97%. Это означает, что между этими двумя функциями существует сильная линейная связь. По мере того как number_doors увеличивается на одну единицу, спальни увеличивается на одну единицу, и наоборот. Эта пара функций кодирует аналогичный шаблон, поэтому мы можем рассматривать их как избыточные.
  • На диагоналях мы видим, что все функции имеют высокую дисперсию. Похоже, все функции актуальны и ни одна из них не является чистым шумом.

Вот как построить ковариационную матрицу.

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
# Load dataset
dataset = pd.read_csv('src/dataset.csv')
pca = PCA(dataset, standardize=True, method='eig')
normalized_dataset = pca.transformed_data
# Covariance Matrix
# bias =True, so dataset is normalized
# rowvar = False, each column represents a variable, i.e., a feature. This way we compute the covariance of features as whole instead of the covariance of each row
covariance_df = pd.DataFrame(data=np.cov(normalized_dataset, bias=True, rowvar=False), columns=dataset.columns)
# Plot Covariance Matrix
plt.subplots(figsize=(20, 20))
sns.heatmap(covariance_df, cmap='Blues', linewidths=.7, annot=True, fmt='.2f', yticklabels=dataset.columns)
plt.show()

PCA на Python

Мы собираемся использовать библиотеку Python statsmodels для выполнения PCA. Вы также можете использовать ScikitLearn, но statsmodels обеспечивает немного больше гибкости. Например, вы можете выбрать, хотите ли вы использовать собственные векторы или разложение по сингулярным значениям.

Итак, для этого примера мы установим следующие флаги в методе statsmodel PCA:

  • Для standardize установлено значение True, поэтому мы стандартизируем данные с нулевым средним и дисперсией 1.
  • Для method установлено значение eig, поэтому собственные векторы ковариационной матрицы становятся нашими главными компонентами.

Мы оставим параметр ncomp незаданным, поэтому PCA вернет все основные компоненты, то есть их столько, сколько функций.

import pandas as pd
from sklearn import preprocessing
# Load dataset
dataset = pd.read_csv('dataset.csv')
# Run PCA
pca = PCA(dataset, standardize=True, method='eig')
components_df = pca.factors

Интерпретация результатов PCA

Итак, components_df - это массив со всеми главными компонентами, то есть собственными векторами ковариационной матрицы.

Но это само по себе мало что говорит нам о данных. Нам нужно найти способ интерпретировать эти результаты и связать их с нашим исходным набором данных.

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

Будет проще, если мы визуализируем корреляционную матрицу. Поверх цветового градиента мы немного подправим график, чтобы:

  • Создайте пространство между ячейками для лучшей читаемости и эстетики с помощью linewidths = .7.
  • Добавьте значение корреляции в каждую ячейку с помощью annot = True. Так будет легче обнаружить различия между значениями ячеек.
  • Усеките значение в каждой ячейке, чтобы оно состояло из 2 значащих цифр, для удобства чтения с помощью fmt = ’. 2f’.

И у нас есть корреляционная матрица 😀

Сразу можно увидеть самые высокие значения корреляции, связанные с первым главным компонентом, comp_00.

Основные компоненты сортируются по степени изменчивости набора данных, который они кодируют. Таким образом, имеет смысл, что первые основные компоненты имеют более высокую корреляцию с функциями набора данных.

Эти функции, связанные с первым главным компонентом, наиболее важны для определения закономерностей в данных.

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

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
# Load dataset
dataset = pd.read_csv('dataset.csv')
# Run PCA
pca = PCA(dataset, standardize=True, method='eig')
components_df = pca.factors
combined_df = pd.concat([dataset, components_df], axis=1)
correlation = combined_df.corr()

# This matrix will have the correlation between:
# 1. feature vs features
# 2. feature vs principal component
# 3. principal component vs principal component
# We're removing part of the output to keep only the correlation between features and principal components
correlation_plot_data = correlation[:-len(components_df.columns)].loc[:, 'comp_00':]

# plot correlation matrix
fig, ax = plt.subplots(figsize=(20, 7))
sns.heatmap(correlation, cmap='YlGnBu', linewidths=.7, annot=True, fmt='.2f')
plt.show()

Как PCA может помочь Мэгги

Матрица корреляции показывает, какие функции коррелируют с первым главным компонентом и, следовательно, какие функции будут изменяться вместе. Один хороший пример, поскольку существует положительная корреляция между первым основным компонентом и спальнями и квадратными метрами, мы можем сказать, что по мере увеличения количества спален или ванных комнат квадрат отснятый материал имеет тенденцию к увеличению.

Но есть также несколько отрицательных корреляций с первым основным компонентом, например, с доступностью общественного транспорта, близостью к центру города и близостью супермаркета. Это показывает, что более крупные дома с более высокой площадью и большим количеством спален будут располагаться дальше от центра города, от супермаркетов и имеют меньшую транспортную доступность.

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

Компромисс: потеря интерпретируемости

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

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

Когда мы сопоставляем черты друг с другом, легче интерпретировать закономерности. Но поскольку основные компоненты кодируют несколько функций, при их построении не ясно:

  • Какие особенности кодирует каждый из основных компонентов,
  • Какая доля каждой функции больше влияет на наблюдаемые нами закономерности.

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

Нагрузки - это веса, применяемые к каждому объекту в линейной комбинации, которая приводит к баллу главного компонента.

Глядя только на первые два основных компонента, мы видим, что:

  • спальни и number_doors содержат больше информации, зафиксированной в первом основном компоненте.
  • паркетные_полы и city_center содержат больше информации во втором основном компоненте.

Вот как можно проверить нагрузки.

import pandas as pd
from statsmodels.multivariate.pca import PCA
# Load dataset
dataset = pd.read_csv('dataset.csv')
pca = PCA(dataset, standardize=True, method='eig')
loadings = pca.loadings
print(loadings)

Снижение размерности

Одно из самых популярных приложений PCA - уменьшение размерности. Это способ создать новое представление набора данных:

  • Меньше, чем исходный набор данных,
  • Сохраняет только свои основные образцы и характеристики.

Выбор основных компонентов для представления уменьшенной версии вашего набора данных - сложная тема сама по себе. Это называется Факторный анализ, потому что мы также можем называть компоненты факторами.

Традиционные методы выбора факторов включают:

  • Критерий Кайзера
  • Объясненная дисперсия
  • Осыпь сюжет

Критерий Кайзера

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

Если бы мы использовали этот метод, мы бы исключили последние три основных компонента.

import pandas as pd
from statsmodels.multivariate.pca import PCA

# Load dataset
dataset = pd.read_csv('src/dataset.csv')
pca = PCA(dataset, standardize=True, method='eig')
eigen_values = pd.DataFrame(data=pca.eigenvals.values, columns=['eigenvalue'])
print(eigen_values)

Объясненная дисперсия

С помощью этого метода вы выбираете общую величину отклонения в наборе данных, который должны кодировать основные компоненты. Обычно эти пороговые значения составляют 80% или 90%.

Если бы мы использовали этот метод, у нас было бы:

  • Первые шесть основных компонентов объясняют чуть более 80% дисперсии,
  • Первые девять основных компонентов примерно объясняют 90% дисперсии в нашем наборе данных.

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

import pandas as pd
from statsmodels.multivariate.pca import PCA
# Load dataset
dataset = pd.read_csv('src/dataset.csv')
pca = PCA(dataset, standardize=True, method='eig')
# Cumulative Variance Explained
cumulative_variance_explained = pd.DataFrame(data=pca.rsquare.values, columns=['cumulative_var'])
print(cumulative_variance_explained)

В статистике R-квадрат - это показатель, используемый для определения того, какая часть дисперсии одной переменной объясняется другой переменной. Отсюда и название этого атрибута модели PCA.

Осыпь сюжет

С помощью осыпи мы выбираем компоненты более наглядно. Мы наносим на график собственное значение для каждого компонента и используем метод локтя для определения точки отсечения.

Идея состоит в том, чтобы проследить за убывающими собственными значениями и посмотреть, где эти значения образуют изгиб. Мы включаем только главный компонент, ведущий к точке локтя.

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

import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.multivariate.pca import PCA
# Load dataset
dataset = pd.read_csv('src/dataset.csv')
pca = PCA(dataset, standardize=True, method='eig')
plt.subplots(figsize=(10, 10))
pca.plot_scree()
plt.show()

Заключение

Надеюсь, вам понравился этот пример. С помощью этого случайно сгенерированного набора данных мы прошли каждый этап PCA и рассмотрели:

  • Как работает PCA.
  • Что такое основные компоненты и как они соотносятся с исходным набором данных.
  • Как решить, какие основные компоненты оставить, если мы хотим сжать наш набор данных.

Спасибо за внимание!