
Метод главных компонент (Principal Component Analysis или же PCA) — алгоритм обучения без учителя, используемый для понижения размерности и выявления наиболее информативных признаков в данных. Его суть заключается в предположении о линейности отношений данных и их проекции на подпространство ортогональных векторов, в которых дисперсия будет максимальной.
Такие вектора называются главными компонентами и они определяют направления наибольшей изменчивости (информативности) данных. Альтернативно суть PCA можно определить как линейное проецирование, минимизирующее среднеквадратичное расстояние между исходными точками и их проекциями.
Ноутбук с данным алгоритмом можно загрузить на Kaggle (eng) и GitHub (rus).
Принцип работы PCA
Изначально матрица признаков обязательно центрируется, чтобы первая главная компонента могла соответствовать направлению максимальной вариации данных, а не просто их среднему значению. Обычно нахождение главных компонент сводится к двум основным методам:
Вычисление собственных векторов и собственных значений ковариационной матрицы данных. Поскольку ковариационная матрица отражает степень линейной связи между различными переменными, то собственные вектора этой матрицы будут задавать направления, вдоль которых дисперсия данных максимальна, а собственные значения — величину этой дисперсии. Собственное значение, соответствующее собственному вектору, характеризует вклад этого вектора в объяснение дисперсии данных и чем больше собственное значение, тем значимее главная компонента. Обычно отбираются только те главные компоненты, которые объясняют заданный уровень дисперсии, например, 95%.
Вычисление сингулярного разложения матрицы данных. Сингулярное разложение — это способ представления любой матрицы в виде произведения трёх других матриц: левой сингулярной матрицы U, диагональной матрицы сингулярных значений S и правой сингулярной матрицы V, где сингулярные значения — это квадратные корни собственных значений ковариационной матрицы данных (именно для этого в данном случае выполняется предварительное центрирование данных), правая сингулярная матрица V будет соответствовать собственным векторам ковариационной матрицы данных, а левая U будет являться проекцией исходных данных на главные компоненты, определённые матрицей V. Таким образом, сингулярное разложение также позволяет выделить главные компоненты, но без необходимости в вычислении ковариационной матрицы. Помимо того, что такое решение более эффективно, оно считается более численно стабильным, поскольку не требует вычисления ковариационной матрицы напрямую, которая может быть плохо обусловлена в случае сильной корреляции признаков. Именно данный подход используется в реализации scikit-learn, но с некоторыми особенностями, рассмотренными ниже.
PCA на основе SVD строится следующим образом:
1) сначала происходит центрирование данных, а также определяется число компонент как минимум между числом образцов и признаков в случае, если число компонент не было задано;
2) далее SVD применяется к центрированной матрице данных;
3) к матрице U применяется метод svd_flip_vector, который находит максимальные по модулю элементы в каждом столбце матрицы U, извлекает их знаки и умножает матрицу U на эти знаки, чтобы гарантировать детерминированный вывод;
4) объяснённая дисперсия для каждой главной компоненты вычисляется как возведённые в квадрат соответствующие сингулярные значения, разделённые на n_samples - 1, а преобразованные данные вычисляются с учётом числа главных компонент по правилу
.
Дополнительные возможности PCA
Коэффициент объяснённой дисперсии каждой главной компоненты, доступный через переменную explained_variance_ratio_, указывает долю дисперсии датасета, лежащей вдоль оси каждой главной компоненты.
Восстановление данных с помощью метода inverse_transform() заключается в применении обратной трансформации проекции PCA вида , где
— матрица из первых d главных компонент. Из этого следует, что данные будут восстановлены с потерями, пропорциональными количеству отброшенной дисперсии исходных данных, а средний квадрат расстояния между исходными и восстановленными данными представляет собой ошибку восстановления (reconstruction error).
Инкрементный PCA, реализованный в виде класса IncrementalPCA, позволяет работать эффективнее с большими наборами данных за счёт их разбиения на мини-пакеты и поштучном хранении в памяти во время обучения.
Рандомизированный PCA, устанавливаемый с помощью параметра svd_solver='randomized', использует стохастический алгоритм для быстрого вычисления приближённых d главных компонент и основан на предположении, что случайная проекция данных на низкоразмерное подпространство может хорошо сохранять их структуру и свойства, однако такой подход может быть менее точным.
Ядерный PCA, реализованный с помощью класса KernelPCA, позволяет выполнять сложные нелинейные проекции с использованием ядерных функций. Как и в случае с SVM, его суть в данном случае заключается в том, что линейная граница решений в многомерном пространстве признаков будет соответствовать сложной нелинейной границе в исходном пространстве.
Альтернативы PCA
Не смотря на то, что метод главных компонент является одним из самых популярных алгоритмов понижения размерности, существуют альтернативы, которые могут быть более предпочтительными в ряде ситуаций, а также в зависимости от типа данных:
LLE (Locally Linear Embedding) — алгоритм создания линейных комбинаций каждой точки из её соседей с последующим восстановлением этих комбинаций в пространстве более низкой размерности, что позволяет сохранить нелинейную геометрию данных и быть полезным для некоторых задач, где глобальные свойства менее важны. С другой стороны, такой подход имеет высокую вычислительную сложность и может быть чувствителен к шуму.
t-SNE (t-Distributed Stochastic Neighbor Embedding) — алгоритм, который преобразует сходства между данными в вероятности и в дальнейшем пытается минимизировать расхождение между распределениями вероятностей в пространстве высокой и низкой размерности. t-SNE эффективен при визуализации данных высокой размерности, однако может искажать глобальную структуру данных, поскольку не учитывает линейные зависимости, а лишь их близость в исходном пространстве.
UMAP (Uniform Manifold Approximation and Projection) — ещё один алгоритм, подходящий для визуализации данных, который основан на идеи, что данные лежат на некотором однородном многообразии, которое можно аппроксимировать с помощью графа соседей. Такой подход учитывает глобальную структуру данных и позволяет лучше адаптироваться к различным типам данных, а также лучше справляться с шумом и выбросами, чем t-SNE.
Autoencoders — тип нейронных сетей, основанный на обучении кодировщика преобразовывать входные данные в низкоразмерное представление, с последующим обучением декодера восстанавливать исходные данные из этого представления. Autoencoders могут также использоваться для сжатия данных, удаления шума и многих других целей.
Импорт необходимых библиотек
import numpy as np from sklearn.decomposition import PCA from sklearn.datasets import load_iris
Реализация на Python с нуля
class SVDPCA: def __init__(self, n_components=None): self.n_components = n_components @staticmethod def svd_flip_vector(U): max_abs_cols_U = np.argmax(np.abs(U), axis=0) # extract the signs of the max absolute values signs_U = np.sign(U[max_abs_cols_U, range(U.shape[1])]) return U * signs_U def fit_transform(self, X): n_samples, n_features = X.shape X_centered = X - X.mean(axis=0) if self.n_components is None: self.n_components = min(n_samples, n_features) U, S, Vt = np.linalg.svd(X_centered) # flip the eigenvector sign to enforce deterministic output U_flipped = self.svd_flip_vector(U) self.explained_variance = (S[:self.n_components] ** 2) / (n_samples - 1) self.explained_variance_ratio = self.explained_variance / np.sum(self.explained_variance) # X_new = X * V = U * S * Vt * V = U * S X_transformed = U_flipped[:, : self.n_components] * S[: self.n_components] return X_transformed
Загрузка датасета
X, y = load_iris(return_X_y=True, as_frame=True) print(X) sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) 0 5.1 3.5 1.4 0.2 1 4.9 3.0 1.4 0.2 2 4.7 3.2 1.3 0.2 3 4.6 3.1 1.5 0.2 4 5.0 3.6 1.4 0.2 .. ... ... ... ... 145 6.7 3.0 5.2 2.3 146 6.3 2.5 5.0 1.9 147 6.5 3.0 5.2 2.0 148 6.2 3.4 5.4 2.3 149 5.9 3.0 5.1 1.8 [150 rows x 4 columns]
Обучение моделей и оценка полученных результатов
Ручная реализация показала идентичные результаты scikit-learn. Как можно заметить, первые 2 главные компоненты объясняют практически 98% дисперсии в данных, что позволяет сократить количество признаков вдвое без особой потери информации. Если бы количество признаков было не 4, а несколько тысяч или миллионов, то это бы позволило существенно сократить время обучения моделей без значительной потери точности (а иногда и с увеличением точности за счёт уменьшения мультиколлинеарности между признаками), что делает PCA и его альтернативы прекрасным дополнением к другим алгоритмам.
PCA
pca = SVDPCA() X_transformed = pca.fit_transform(X) print('transformed data', X_transformed[:10], '', sep='\n') print('explained_variance', pca.explained_variance) print('explained_variance_ratio', pca.explained_variance_ratio) transformed data [[-2.68412563e+00 3.19397247e-01 -2.79148276e-02 -2.26243707e-03] [-2.71414169e+00 -1.77001225e-01 -2.10464272e-01 -9.90265503e-02] [-2.88899057e+00 -1.44949426e-01 1.79002563e-02 -1.99683897e-02] [-2.74534286e+00 -3.18298979e-01 3.15593736e-02 7.55758166e-02] [-2.72871654e+00 3.26754513e-01 9.00792406e-02 6.12585926e-02] [-2.28085963e+00 7.41330449e-01 1.68677658e-01 2.42008576e-02] [-2.82053775e+00 -8.94613845e-02 2.57892158e-01 4.81431065e-02] [-2.62614497e+00 1.63384960e-01 -2.18793179e-02 4.52978706e-02] [-2.88638273e+00 -5.78311754e-01 2.07595703e-02 2.67447358e-02] [-2.67275580e+00 -1.13774246e-01 -1.97632725e-01 5.62954013e-02]] explained_variance [4.22824171 0.24267075 0.0782095 0.02383509] explained_variance_ratio [0.92461872 0.05306648 0.01710261 0.00521218]
PCA (scikit-learn)
sk_pca = PCA() sk_X_transformed = sk_pca.fit_transform(X) print('sk transformed data', sk_X_transformed[:10], '', sep='\n') print('sk explained_variance', sk_pca.explained_variance_) print('sk explained_variance_ratio_', sk_pca.explained_variance_ratio_) sk transformed data [[-2.68412563e+00 3.19397247e-01 -2.79148276e-02 -2.26243707e-03] [-2.71414169e+00 -1.77001225e-01 -2.10464272e-01 -9.90265503e-02] [-2.88899057e+00 -1.44949426e-01 1.79002563e-02 -1.99683897e-02] [-2.74534286e+00 -3.18298979e-01 3.15593736e-02 7.55758166e-02] [-2.72871654e+00 3.26754513e-01 9.00792406e-02 6.12585926e-02] [-2.28085963e+00 7.41330449e-01 1.68677658e-01 2.42008576e-02] [-2.82053775e+00 -8.94613845e-02 2.57892158e-01 4.81431065e-02] [-2.62614497e+00 1.63384960e-01 -2.18793179e-02 4.52978706e-02] [-2.88638273e+00 -5.78311754e-01 2.07595703e-02 2.67447358e-02] [-2.67275580e+00 -1.13774246e-01 -1.97632725e-01 5.62954013e-02]] sk explained_variance [4.22824171 0.24267075 0.0782095 0.02383509] sk explained_variance_ratio_ [0.92461872 0.05306648 0.01710261 0.00521218]
Преимущества и недостатки
Преимущества:
понижение размерности с сохранением большого количества информации, что также позволяет визуализировать данные высокой размерности в двумерном или трёхмерном пространстве;
не только позволяет значительно ускорить обучение, но и уменьшить переобучение моделей в ряде случаев;
может использоваться для сжатия данных.
Недостатки:
неизбежная потеря части информации в данных;
поиск только линейной зависимости в данных (в обычном PCA);
отсутствие смыслового значения главных компонент из-за трудности их связывания с реальными признакам.
Дополнительные источники
Статьи:
«A Tutorial on Principal Component Analysis», Jonathon Shlens;
«Locally Linear Embedding and its Variants: Tutorial and Survey», Benyamin Ghojogh, Ali Ghodsi, Fakhri Karray, Mark Crowley;
«Theoretical Foundations of t-SNE for Visualizing High-Dimensional Clustered Data», T. Tony Cai, Rong Ma;
«UMAP: Uniform Manifold Approximation and Projection for Dimension Reduction», Leland McInnes, John Healy, James Melville;
«Deep Autoencoders for Dimensionality Reduction of High-Content Screening Data», Lee Zamparo, Zhaolei Zhang.
Документация:
Видео:
