Многомерный набор данных — это набор данных с большим количеством столбцов (или переменных). Такой набор данных представляет много проблем математика или компьютеры. Цель состоит в том, чтобы уменьшить размеры с помощью методов уменьшения размеров.
Хорошей новостью является то, что переменные (или так называемые признаки) часто коррелируют — в многомерных данных «поверхностно» доминирует небольшое количество простых переменных.
Мы можем найти подмножество переменных для представления того же уровня информации в данных или преобразовать переменные в новый набор переменных, не теряя много информации. Хотя высокопроизводительные вычисления могут каким-то образом обрабатывать данные большой размерности, во многих приложениях по-прежнему необходимо уменьшать размерность исходных данных.
Анализ главных компонентов (PCA), вероятно, является наиболее популярным методом, когда речь идет об уменьшении размерности. В этой статье я начну с PCA, а затем представлю другие методы уменьшения размерности. Код Python будет включен в каждый метод.
Исследователи данных могут использовать методы уменьшения размерности для выявления аномалий. Почему? Разве мы не хотим просто уменьшить размерность? Интуиция кроется в самих выбросах. DMHawkins сказал: «Отклонение — это наблюдение, которое настолько сильно отличается от других наблюдений, что вызывает подозрение, что оно было создано другим механизмом. Как только размеры уменьшаются до меньшего количества основных измерений, идентифицируются шаблоны, а затем выявляются выбросы.
Анализ основных компонентов PCA
Идея анализа главных компонентов (PCA) состоит в том, чтобы уменьшить размерность набора данных, состоящего из большого количества связанных переменных, при сохранении как можно большей дисперсии данных. PCA находит набор новых переменных, исходные переменные которых являются только их линейными комбинациями. Новые переменные называются главными компонентами (PC). Эти главные компоненты ортогональны: в трехмерном случае главные компоненты перпендикулярны друг другу. X не может быть представлен Y или Y не может быть представлен Z.
На следующем рисунке показана интуиция PCA: он «вращает» оси для лучшего согласования с вашими данными. Первый основной компонент будет охватывать большую часть дисперсии данных, за ним следуют второй, третий и так далее. Поэтому новые данные будут иметь меньше измерений.
Давайте используем набор данных радужной оболочки, чтобы проиллюстрировать PCA:
# Используйте набор данных радужной оболочки, чтобы проиллюстрировать PCA:
импортировать панд как pd
URL = "https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"
# загружает набор данных в Pandas DataFrame
df = pd.read_csv(url, names=['длина чашелистика','ширина чашелистика','длина лепестка','ширина лепестка','цель'])
дф.голова()

Обратите внимание, что этот набор данных IRIS поставляется с целевой переменной. В PCA вы только преобразуете переменные X без целевой переменной Y.
Все переменные должны быть в одном масштабе перед применением PCA, иначе в результате будет доминировать признак с большими значениями.
Ниже я использую StandardScaler в scikit-learn для стандартизации функций набора данных в единичном масштабе (среднее значение = 0 и дисперсия = 1).
из sklearn.preprocessing импортировать StandardScaler
переменные = ['длина чашелистика', 'ширина чашелистика', 'длина лепестка', 'ширина лепестка']
x = df.loc[:, переменные].значения
y = df.loc[:,['цель']].значения
x = StandardScaler().fit_transform(x)
х = pd. DataFrame (х)

В исходных данных есть четыре характеристики. Таким образом, PCA будет поставлять такое же количество основных компонентов.
из sklearn.decomposition импортировать PCA
ПКА = ПКА()
x_pca = pca.fit_transform(x)
x_pca = pd.DataFrame(x_pca)
x_pca.head()
Какие дисперсии объясняются каждой из главных компонент? Используйте pca.explained_variance_ratio_, чтобы вернуть вектор дисперсии:
объясненная_дисперсия = pca.explained_variance_ratio_
объясненная_дисперсиямассив ([0,72770452, 0,23030523, 0,03683832, 0,00515193])
Он показывает, что первая главная компонента представляет собой дисперсию 72,22 %, вторая, третья и четвертая представляют собой дисперсию 23,9 %, 3,68 % и 0,51 % соответственно. Можно сказать, что 72,22 + 23,9 = 96,21% информации захвачено первой и второй главными компонентами.
Мы часто хотим сохранить только значимые функции и удалить второстепенные. Эмпирическое правило состоит в том, чтобы сохранить основные основные компоненты, которые фиксируют большую дисперсию, и игнорировать мелкие.
Мы можем проследить полученные результаты используя первые два компонента. Давайте добавим целевую переменную y к новым данным x_pca:
x_pca['цель']=y
x_pca.columns = ['ПК1','ПК2','ПК3','ПК4','цель']
x_pca.head()

Результат показывает, что данные являются разделимыми в новом пространстве.
импортировать matplotlib.pyplot как plt
рис = пл цифра ()
топор = fig.add_subplot (1,1,1)
ax.set_xlabel('Основной компонент 1')
ax.set_ylabel('Основной компонент 2')
ax.set_title('2 компонента PCA')
target = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
цвета = ['r', 'g', 'b']
для цели, цвет в почтовом индексе (цели, цвета):
indexToKeep = x_pca['target'] == цель
ax.scatter(x_pca.loc[indicesToKeep, 'PC1']
, x_pca.loc[indicesToKeep, 'PC2']
, с = цвет
, с = 50)
ax.legend (цели)
топор.сетка()

Как мы используем PCA для обнаружения выбросов? Позвольте мне дать вам интуицию. После преобразования «нормальные» точки данных будут выровнены по собственным векторам (новым осям) с небольшими собственными значениями. Выбросы далеки от собственных векторов с большими собственными значениями. Следовательно, расстояния между каждой точкой данных и собственными векторами становятся мерой выброса. Большое расстояние указывает на аномалию.
Ядро ACP (KPCA)
PCA применяет линейное преобразование, которое является лишь его ограничением. KACP расширяет PCA до нелинейности. Сначала он сопоставляет исходные данные с нелинейным пространством признаков (обычно многомерным), а затем применяет PCA для извлечения основных компонентов из этого пространства. Это можно понять по рисунку (В). График слева показывает, что синюю и красную точки нельзя разделить с помощью линейного преобразования. Но если все точки спроецировать на трехмерное пространство, результат станет линейно разделимым! Затем мы применяем PCA для разделения компонентов.
Откуда берется интуиция? Почему разделение компонентов становится проще в многомерном пространстве? Это должно восходить к теории Вапника-Червоненкиса (ВК). Он говорит, что отображение в многомерном пространстве часто обеспечивает большую мощность классификации.
Следующий код Python создает круговой путь, состоящий из красных и синих точек. Очевидно, что нет возможности разделить красную и синюю точки линией (линейное разделение).
печать (__doc__)
импортировать numpy как np
импортировать matplotlib.pyplot как plt
из sklearn.decomposition импортировать PCA, KernelPCA
из sklearn.datasets импортировать make_circlesnp.random.seed (0)
x, y = make_circles (n_samples = 400, фактор = 0,3, шум = 0,05)plt.figure(figsize=(10,10))
plt.subplot(2, 2, 1, аспект='равно')
plt.title("Исходное пространство")
красные = у == 0
блюз = у == 1plt.scatter(X[красные, 0], X[красные, 1], c="красный",s=20, edgecolor='k')
plt.scatter(X[синий, 0], X[синий, 1], c="синий",s=20, edgecolor='k')
plt.xlabel("$x_1$")
plt.ylabel("$x_2$")
Однако, когда мы проецируем окружность в пространство более высокого измерения и разделяем ее с помощью PCA, наблюдения данных относительно первой и второй главных компонент можно разделить! Ниже приведен результат, в котором точки нанесены на график относительно первой и второй главных компонент. Я рисую линию, чтобы разделить красные и синие точки.
В KernelPCA мы указываем kernel='rbf', что является радиальной базисной функцией или евклидовым расстоянием. RBF обычно используются в качестве ядра в методах машинного обучения, таких как машина опорных векторов (SVM).
kpca = KernelPCA (ядро = «rbf», fit_inverse_transform = True, гамма = 10)
X_kpca = kpca.fit_transform(X)
ПКА = ПКА()
X_pca = pca.fit_transform(X)plt.scatter (X_kpca [красные, 0], X_kpca [красные, 1], c = «красный», s = 20, edgecolor = 'k')
plt.scatter (X_kpca [синий, 0], X_kpca [синий, 1], c = «синий», s = 20, edgecolor = 'k')
х = np.linspace (-1, 1, 1000)
plt.plot(x, -0,1*x, linestyle='solid')
plt.title("Прогноз KPCA")
plt.xlabel(r"1-й главный компонент в пространстве, индуцированный $\phi$")
plt.ylabel («2-й компонент»)

Если мы укажем, что ядро является «линейным», как в приведенном ниже коде (KernelPCA(kernel='linear'), оно станет стандартным PCA только с линейным преобразованием, а красная и синяя точки неразделимы.
kpca = KernelPCA (kernel = «линейный», fit_inverse_transform = True, гамма = 10)
X_kpca = kpca.fit_transform(X)
ПКА = ПКА()
X_pca = pca.fit_transform(X)plt.scatter (X_kpca [красные, 0], X_kpca [красные, 1], c = «красный», s = 20, edgecolor = 'k')
plt.scatter (X_kpca [синий, 0], X_kpca [синий, 1], c = «синий», s = 20, edgecolor = 'k')
х = np.linspace (-1, 1, 1000)
plt.plot(x, -0,1*x, linestyle='solid')
plt.title("Прогноз KPCA")
plt.xlabel(r"1-й главный компонент в пространстве, индуцированный $\phi$")
plt.ylabel («2-й компонент»)

Линейный дискриминантный анализ LDA
Происхождение LDA отличается от PCA. PCA — это метод обучения без учителя, который преобразует исходную функциональность в набор новых функций. Нас не волнует, сможет ли новый набор функций обеспечить наилучшую дискриминационную способность для целевой переменной. Напротив, линейный дискриминантный анализ (LDA) стремится сохранить как можно большую дискриминационную способность для зависимой переменной, при этом проецируя исходную матрицу данных на пространство с меньшими размерностями.
LDA — это метод контролируемого обучения. Он использует классы зависимой переменной для разделения пространства предикторов на области. Все регионы должны иметь линейные границы. Откуда пошло название «линейка». Модель предсказывает, что все наблюдения в регионе относятся к одному и тому же классу зависимой переменной.
LDA достигает вышеуказанной цели в три основных шага. Во-первых, он вычисляет разделимость между различными классами зависимой переменной, называемую дисперсией между классами, как показано в (1) на рисунке LDA. Во-вторых, он вычисляет расстояние между средним значением и выборками каждого класса, называемое внутриклассовой дисперсией, как показано в (2). Затем он строит пространство более низкой размерности с этим критерием: максимизация межклассовой дисперсии и минимизация внутриклассовой дисперсии.
Решением этого критерия является вычисление собственных значений и собственных векторов. Результирующие собственные векторы представляют направления нового пространства, а соответствующие собственные значения представляют длину собственных векторов. Таким образом, каждый собственный вектор представляет собой ось пространства LDA, а собственное значение представляет собой длину этого собственного вектора.
Я буду использовать набор данных «Качество красного вина» для конкурса Kaggle. Этот набор данных имеет 11 входных переменных и одну выходную переменную «качество».
импортировать matplotlib.pyplot как plt
из sklearn.decomposition импортировать PCA
из sklearn.discriminant_analysis импортировать LinearDiscriminantAnalysis
вино = pd.read_csv('winequality-red.csv')
вино.голова()

Для простоты я группирую выходную переменную по трем значениям. вино['качество2'] = np.where(вино['качество']<=4,1, np.where(вино['качество']<=6,2,3)).

Следующий код выполняет PCA и LDA.
X = wine.drop (столбцы = ['качество', 'качество2'])
у = вино['качество2']
target_names = np.unique(y)
target_namesPCA = PCA (n_components = 2)
X_r = pca.fit(X).transform(X)lda = LinearDiscriminantAnalysis (n_components = 2)
X_r2 = lda.fit(X, y).transform(X)
Затем постройте результаты PCA и LDA:
# Объяснение процентной дисперсии для каждого компонента
print('объясненный коэффициент дисперсии (первые два компонента): %s'
% ул(pca.explained_variance_ratio_))plt.figure()
colors = ['темно-синий', 'бирюзовый', 'темно-оранжевый']
лв = 2для цвета, я, target_name в zip (цвета, target_names, target_names):
plt.scatter(X_r[y == i, 0], X_r[y == i, 1], color=color, alpha=.8, lw=lw,
метка=имя_цели)
plt.legend(loc='лучший', shadow=False, точки рассеивания=1)
plt.title('PCA набора данных WINE')plt.figure()
для цвета, я, target_name в zip (цвета, target_names, target_names):
plt.scatter(X_r2[y == i, 0], X_r2[y == i, 1], альфа=.8, цвет=цвет,
метка=имя_цели)
plt.legend(loc='лучший', shadow=False, точки рассеивания=1)
plt.title('LDA набора данных WINE')plt.show()

LDA подходит для задачи классификации нескольких классов.
Разложение по сингулярным значениям SVD
SVD — это метод синтеза данных, аналогичный PCA. Он извлекает важные функции из данных. Но есть еще одно преимущество SVD: перестроение исходного набора данных в небольшой набор данных. Таким образом, он имеет широкое применение, например, для сжатия изображений. Например, если у вас есть изображение размером 32*32 = 1024 пикселя, SVD может суммировать его до 66 пикселов. 66 пикселей могут восстанавливать изображения размером 32*32 пикселя, не пропуская никакой важной информации.
SVD сыграла важную роль в линейной алгебре, но кажется «не такой известной, как должна быть», как указано в классическом учебнике «Линейная алгебра и ее приложения» Гилберта Стрэнга. Чтобы правильно ввести SVD, важно начать с матричной операции. Если A — симметричная вещественная матрица размера n × n, существуют ортогональная матрица V и диагональ D такие, что

Столбцы V являются собственными векторами для A, а диагональные элементы D являются собственными значениями A. Этот процесс называется разложением по собственным значениям, или EVD, для матрицы A. Он говорит нам, как выбрать ортонормированные базы так, чтобы преобразование представляется матрицей. с самой простой возможной формой, то есть по диагонали. (Для читателей, которые хотят повторить шаги по диагонализации матрицы, вот хороший пример.) Термин ортонормированный означает, что два вектора ортогональны или перпендикулярны.
Расширяя симметричную матрицу, SVD работает с любой реальной матрицей A размером m × n. Для действительной матрицы A размера m × n существуют ортогональная матрица размера m × m U, ортогональная матрица размера m × m V и диагональная матрица размера m × n такие, что

Обратите внимание, что ортогональная матрица — это квадратная матрица, произведение самой себя на обратную ей матрицу — единичная матрица. Диагональная матрица — это матрица, в которой все элементы, кроме диагональных, равны нулю.
Ниже я снова воспользуюсь набором данных радужной оболочки, чтобы показать вам, как применять SVD.
из импорта numpy *
оператор импорта
импортировать matplotlib.pyplot как plt
импортировать панд как pd
из импорта numpy.linalg *URL = "https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"
# загружает набор данных в Pandas DataFrame
df = pd.read_csv(url, names=['длина чашелистика','ширина чашелистика','длина лепестка','ширина лепестка','цель'])# Только переменные X
data = df[['длина чашелистика','ширина чашелистика','длина лепестка','ширина лепестка']]#рассчитать СВД
n = 2 # Возьмем два сингулярных значения
U, s, V = linalg.svd(данные)# eye() создает матрицу с единицами по диагонали и нулями в других местах
Sig = мат (глаз (n) * s [: n])
новые данные = U[:,:n]
новые данные = pd.DataFrame (новые данные)
newdata.columns=['СВД1','СВД2']
новые данные.голова()

Вы можете сравнить результат SVD с PCA. Оба получают схожие результаты.
# Добавьте фактическую цель к данным, чтобы построить ее
новые данные['цель']=df['цель']рис = пл цифра ()
топор = fig.add_subplot (1,1,1)
ax.set_xlabel('СВД 1')
ax.set_ylabel('СВД 2')
ax.set_title('СВД')
target = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
цвета = ['r', 'g', 'b']
для цели, цвет в почтовом индексе (цели, цвета):
indexToKeep = новые данные ['цель'] == цель
ax.scatter(newdata.loc[indicesToKeep, 'SVD1']
, newdata.loc[indicesToKeep, 'SVD2']
, с = цвет
, с = 50)
ax.legend (цели)
топор.сетка()

Вложение t-распределенного стохастического соседа (t-SNE)
t-SNE разработан Лоренсом ван дер Маатен и Геоггреем Хинтоном. Это алгоритм инструмент машинного обучения для визуализации, отличающийся интеграцией многомерных данных в двух- или трехмерное низкомерное пространство.

Как лучше всего представить трехмерную швейцарскую булочку выше в двухмерной? Интуитивно мы хотим «развернуть» рулет в лепешку. В математике это означает, что подобные точки станут близкими точками, а разные точки станут удаленными точками.
На следующем рисунке показан другой пример. Это трехмерный тетраэдр с точками данных, сгруппированными в углах вершин. Если мы просто сведем трехмерный граф к двумерному, как это делает панель (А), это не сработает, потому что группа (А) станет центральным кластером. Напротив, панель (B), вероятно, представляет собой лучшую двухмерную экспозицию, которая сохраняет дальние расстояния между группами (A)–(E), сохраняя при этом локальные расстояния точек в каждой группе. t-SNE, метод нелинейного уменьшения размерности, предназначен для сохранения локальных окрестностей. Если набор точек сгруппирован вместе на графике t-SNE, мы можем быть достаточно уверены, что эти точки близки друг к другу.

t-SNE моделирует сходство между точками. Как он определяет сходство? Во-первых, он определяется евклидовым расстоянием между точками Xi и Xj. Во-вторых, он определяется как условная вероятность того, что «сходство точки данных i с точкой j является условной вероятностью p того, что точка i выберет данные j в качестве своего соседа, если бы другие соседи были выбраны на основе их вероятностей при распределении Гаусса. В следующем условном выражении, если точка j ближе к точке i, чем другие точки, она имеет более высокую вероятность (обратите внимание на отрицательный знак) быть выбранной.

t-SNE стремится как можно лучше сопоставить вышеуказанную условную вероятность p между j и i с помощью низкоразмерного пространства q между точками Yi и Yj, как показано ниже. Вероятность q соответствует распределению Стьюдента-t с толстым хвостом, откуда берется «t» в t-SNE.

Следующим шагом является нахождение Yi таким образом, чтобы q-распределение максимально приближалось к p-распределению. t-SNE использует метод оптимизации градиентного спуска для поиска значений.
Ниже я покажу, как метод t-SNE используется с набором данных по радужной оболочке.
из sklearn.manifold импортировать TSNE
из sklearn.datasets импортировать load_iris
из sklearn.decomposition импортировать PCA
импортировать matplotlib.pyplot как plt
диафрагма = load_iris()
X_tsne = TSNE (learning_rate = 100).fit_transform (iris.data)
X_pca = PCA().fit_transform(радужная оболочка.данные)
Таблица цифра (figsize = (10, 5))
plt.subplot(121)
plt.scatter(X_tsne[:, 0], X_tsne[:, 1], c=iris.target)
plt.subplot(122)
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=iris.target)
