machinelearningmastery.ru

Машинное обучение, нейронные сети, искусственный интеллект
Header decor

Home

Методы сокращения размеров с Python

Дата публикации Jun 22, 2019

Почему нам нужно уменьшить размерность?

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

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

Анализ основных компонентов (PCA)

Идея анализа главных компонентов (PCA) состоит в том, чтобы уменьшить размерность набора данных, состоящего из большого числа связанных переменных, сохраняя при этом как можно большую дисперсию данных. PCA находит набор новых переменных, исходные переменные которых представляют собой просто их линейные комбинации. Новые переменные называютсяОсновные компоненты (ПК), Эти основные компонентыортогональный: В трехмерном случае главные компоненты перпендикулярны друг другу. X не может быть представлен Y или Y не может быть представлен Z.

На рисунке (A) показана интуиция PCA: он «вращает» оси, чтобы лучше соответствовать вашим данным. Первый основной компонент фиксирует большую часть дисперсии в данных, затем следует второй, третий и т. Д. В результате новые данные будут иметь меньше измерений.

Рисунок (A): PCA

Давайте используем набор данных iris для иллюстрации PCA:

# Use the iris dataset to illustrate PCA:
import pandas as pd
url = “https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"
# load dataset into Pandas DataFrame
df = pd.read_csv(url, names=[‘sepal length’,’sepal width’,’petal length’,’petal width’,’target’])
df.head()
IRIS набор данных

Все переменные должны быть в одном масштабе перед применением PCA, в противном случае функция с большими значениями будет доминировать в результате. Ниже я используюStandardScalerв scikit-learn стандартизировать функции набора данных в единичном масштабе (среднее = 0 и дисперсия = 1).

from sklearn.preprocessing import StandardScaler
variables = [‘sepal length’, ‘sepal width’, ‘petal length’, ‘petal width’]
x = df.loc[:, variables].values
y = df.loc[:,[‘target’]].values
x = StandardScaler().fit_transform(x)
x = pd.DataFrame(x)
Стандартизированные функции

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

from sklearn.decomposition import PCA
pca = PCA()
x_pca = pca.fit_transform(x)
x_pca = pd.DataFrame(x_pca)
x_pca.head()
Основные компоненты для набора данных IRIS

Какие различия объясняются каждым из основных компонентов? использованиеpca.explained_variance_ratio_вернуть вектор дисперсии:

explained_variance = pca.explained_variance_ratio_
explained_variancearray([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[‘target’]=y
x_pca.columns = [‘PC1’,’PC2',’PC3',’PC4',’target’]
x_pca.head()

Результат показывает, что данные отделимы в новом пространстве.

import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.set_xlabel(‘Principal Component 1’)
ax.set_ylabel(‘Principal Component 2’)
ax.set_title(‘2 component PCA’)
targets = [‘Iris-setosa’, ‘Iris-versicolor’, ‘Iris-virginica’]
colors = [‘r’, ‘g’, ‘b’]
for target, color in zip(targets,colors):
indicesToKeep = x_pca[‘target’] == target
ax.scatter(x_pca.loc[indicesToKeep, ‘PC1’]
, x_pca.loc[indicesToKeep, ‘PC2’]
, c = color
, s = 50)
ax.legend(targets)
ax.grid()

Ядро PCA (KPCA)

PCA применяет линейное преобразование, которое является его ограничением.Ядро PCAрасширяет PCA до нелинейности. Сначала он отображает исходные данные в некоторое пространство нелинейных объектов (обычно это более высокое измерение), затем применяет PCA для извлечения основных компонентов в этом пространстве. Это можно понять по рисунку (B). График слева показывает синие и красные точки, которые нельзя разделить с помощью линейного преобразования. Но если все точки проецируются на трехмерное пространство, результат становится линейно разделимым! Затем мы применяем PCA для разделения компонентов.

Откуда приходит интуиция? Почему разделение компонентов становится легче в пространстве более высокого измерения? Это должно вернуться к теории Vapnik-Chervonenkis (VC). Он говорит, что отображение в пространство более высокого измерения часто обеспечивает большую степень классификации.

Рисунок (B): ядро ​​PCA (KPCA)

Следующий код Python создает круговую диаграмму, состоящую из красных и синих точек. Очевидно, что нет возможности разделить красные и синие точки линией (линейное разделение).

print(__doc__)
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA, KernelPCA
from sklearn.datasets import make_circlesnp.random.seed(0)
X, y = make_circles(n_samples=400, factor=.3, noise=.05)plt.figure(figsize=(10,10))
plt.subplot(2, 2, 1, aspect='equal')
plt.title("Original space")
reds = y == 0
blues = y == 1plt.scatter(X[reds, 0], X[reds, 1], c="red",s=20, edgecolor='k')
plt.scatter(X[blues, 0], X[blues, 1], c="blue",s=20, edgecolor='k')
plt.xlabel("$x_1$")
plt.ylabel("$x_2$")

Тем не менее, когда мы проецируем круг в пространство более высокого измерения и разделяем его с помощью PCA, полученные первый и второй главные компоненты разделяются! Ниже приведен результат построения точек относительно первого и второго основных компонентов. Я рисую линию, чтобы отделить красные и синие точки. В KernelPCA мы указываем kernel = ’rbf’, который являетсяРадиальная базисная функцияили Эклидийское расстояние. RBF обычно используются в качестве ядра в методах машинного обучения, таких какМашина опорных векторов (SVM)

kpca = KernelPCA(kernel=”rbf”, fit_inverse_transform=True, gamma=10)
X_kpca = kpca.fit_transform(X)
pca = PCA()
X_pca = pca.fit_transform(X)plt.scatter(X_kpca[reds, 0], X_kpca[reds, 1], c=”red”,s=20, edgecolor=’k’)
plt.scatter(X_kpca[blues, 0], X_kpca[blues, 1], c=”blue”,s=20, edgecolor=’k’)
x = np.linspace(-1, 1, 1000)
plt.plot(x, -0.1*x, linestyle=’solid’)
plt.title(“Projection by KPCA”)
plt.xlabel(r”1st principal component in space induced by $\phi$”)
plt.ylabel(“2nd component”)

Если мы указываем ядро ​​как «линейное» в качестве кода ниже (KernelPCA (kernel = «linear»), оно становится стандартным PCA с только линейным преобразованием, а красные и синие точки не разделяются.

kpca = KernelPCA(kernel=”linear”, fit_inverse_transform=True, gamma=10)
X_kpca = kpca.fit_transform(X)
pca = PCA()
X_pca = pca.fit_transform(X)plt.scatter(X_kpca[reds, 0], X_kpca[reds, 1], c=”red”,s=20, edgecolor=’k’)
plt.scatter(X_kpca[blues, 0], X_kpca[blues, 1], c=”blue”,s=20, edgecolor=’k’)
x = np.linspace(-1, 1, 1000)
plt.plot(x, -0.1*x, linestyle=’solid’)
plt.title(“Projection by KPCA”)
plt.xlabel(r”1st principal component in space induced by $\phi$”)
plt.ylabel(“2nd component”)

Линейный Дискриминантный Анализ (LDA)

Происхождение LDA отличается от PCA. PCA - это метод обучения без учителя, который преобразует исходные функции в набор новых функций. Мы не заботимся о том, может ли новый набор функций обеспечить лучшую дискриминационную силу для целевой переменной. В отличие от этого, Линейный Дискриминантный Анализ (LDA) стремится сохранить как можно большую дискриминационную силу для зависимой переменной, проецируя исходную матрицу данных в пространство более низкого измерения. LDA - тип контролируемой техники обучения. Он использует классы в зависимой переменной, чтобы разделить пространство предикторов нарайоны, Всерайоныдолжен иметьлинейныйграницы. Таким образом, имялинейныйпроисходит от. Модель предсказывает, что все наблюдения в пределах региона принадлежат одному и тому же классу зависимой переменной.

LDA достигает вышеуказанной цели в три основных этапа. Во-первых, он вычисляет разделимость между различными классами зависимой переменной, которая называетсямежклассовая дисперсия, как показано в (1) на рисунке LDA. Во-вторых, он вычисляет расстояние между средним и выборками каждого класса, которое называетсявнутриклассовая дисперсия,как показано в (2). Затем он строит пространство нижних измерений по этому критерию: максимизация межклассовой дисперсии и минимизация внутриклассовой дисперсии. Решением этого критерия является вычисление собственных значений и собственных векторов. Результирующие собственные векторы представляют направления нового пространства, а соответствующие собственные значения представляют длину собственных векторов. Таким образом, каждый собственный вектор представляет одну ось пространства LDA, а собственное значение представляет длину этого собственного вектора.

Рисунок: LDA

Я буду использовать «Качество красного винаНабор данных в конкурсе Kaggle. Этот набор данных имеет 11 входных переменных и одну выходную переменную «качество».

import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
wine = pd.read_csv(‘winequality-red.csv’)
wine.head()

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

Следующий код выполняет PCA и LDA.

X = wine.drop(columns=[‘quality’,’quality2'])
y = wine[‘quality2’]
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:

# Percentage of variance explained for each components
print(‘explained variance ratio (first two components): %s’
% str(pca.explained_variance_ratio_))plt.figure()
colors = [‘navy’, ‘turquoise’, ‘darkorange’]
lw = 2for color, i, target_name in zip(colors, target_names, target_names):
plt.scatter(X_r[y == i, 0], X_r[y == i, 1], color=color, alpha=.8, lw=lw,
label=target_name)
plt.legend(loc=’best’, shadow=False, scatterpoints=1)
plt.title(‘PCA of WINE dataset’)plt.figure()
for color, i, target_name in zip(colors, target_names, target_names):
plt.scatter(X_r2[y == i, 0], X_r2[y == i, 1], alpha=.8, color=color,
label=target_name)
plt.legend(loc=’best’, shadow=False, scatterpoints=1)
plt.title(‘LDA of WINE dataset’)plt.show()

Разложение по сингулярным значениям (SVD)

SVD - это метод обобщения данных, аналогичный PCA. Он извлекает важные данные из данных. Но есть еще одно преимущество SVD: реконструкция исходного набора данных в небольшой набор данных. Так что он имеет широкие возможности, такие как сжатие изображений. Например, если у вас есть изображение размером 32 * 32 = 1024 пикселя, SVD может суммировать его в 66 пикселей. 66 пикселей могут получить 32 * 32 пикселей изображения, не пропуская никакой важной информации.

SVD играет важную роль в линейной алгебре, но кажется, что она «не так известна, как должна быть», как сказано в классическом учебнике «Линейная алгебра и ее приложения» Гилберта Странга. Чтобы правильно внедрить SVD, важно начать с матричной операции. Если A симметричное вещественноеn × nматрица, существует ортогональная матрицаВи диагональDтакой, что

КолонныВявляются собственными векторами для A и диагональными элементамиDявляются собственными значениями А. Этот процесс называетсяРазложение по собственным значениям, илиEVDдля матрицы, В нем рассказывается, как выбирать ортонормированные базисы, чтобы преобразование представляло собой матрицу с самой простой из возможных форм, то есть диагональю. (Для читателей, которые хотели бы пройтись по шагам для диагонализации матрицы,Вотхороший пример.)

Расширяя симметричную матрицу, SVD работает с любым реальнымм × нматрица, Учитывая настоящий м× nматрицасуществует ортогональноем × мматрицаU,ортогональная матрицам × м В,и диагональм × нматрицаΣтакой, что

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

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

from numpy import *
import operator
import matplotlib.pyplot as plt
import pandas as pd
from numpy.linalg import *url = “https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"
# load dataset into Pandas DataFrame
df = pd.read_csv(url, names=[‘sepal length’,’sepal width’,’petal length’,’petal width’,’target’])# Only the X variables
data = df[[‘sepal length’,’sepal width’,’petal length’,’petal width’]]#calculate SVD
n = 2 # We will take two Singular Values
U, s, V = linalg.svd( data )# eye() creates a matrix with ones on the diagonal and zeros elsewhere
Sig = mat(eye(n)*s[:n])
newdata = U[:,:n]
newdata = pd.DataFrame(newdata)
newdata.columns=[‘SVD1’,’SVD2']
newdata.head()

Вы можете сравнить результат SVD с результатом PCA. Оба достигают схожих результатов.

# Add the actual target to the data in order to plot it
newdata[‘target’]=df[‘target’]fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.set_xlabel(‘SVD 1’)
ax.set_ylabel(‘SVD 2’)
ax.set_title(‘SVD’)
targets = [‘Iris-setosa’, ‘Iris-versicolor’, ‘Iris-virginica’]
colors = [‘r’, ‘g’, ‘b’]
for target, color in zip(targets,colors):
indicesToKeep = newdata[‘target’] == target
ax.scatter(newdata.loc[indicesToKeep, ‘SVD1’]
, newdata.loc[indicesToKeep, ‘SVD2’]
, c = color
, s = 50)
ax.legend(targets)
ax.grid()
Рисунок: СВД

Tстохастическое вложение соседей (t-SNE)

T-SNE разработанЛорен ван дер Маатен и Джеогри Хинтон, Это алгоритм машинного обучения для визуализации, который представляет вложение многомерных данных в низкоразмерное пространство двух или трех измерений.

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

Рисунок (C) показывает другой пример Это трехмерный тетраэдр с кластеризацией точек данных в углах вершин. Если мы просто свернем 3-мерный график в 2-мерный график, как это делает Panel (A), он не будет работать хорошо, потому что группа (A) становится центральным кластером. В отличие от этого, панель (B), вероятно, является лучшей двумерной выставкой, которая сохраняет большие расстояния между кластерами (A) - (E), в то же время сохраняя локальные расстояния точек в каждом кластере.T-SNE, метод нелинейного уменьшения размера, предназначен для сохранения локальных окрестностей. Если набор точек сгруппирован вместе на графике t-SNE, мы можем быть достаточно уверены, что эти точки расположены близко друг к другу.

Рисунок (С): t-SNE

T-SNE моделирует сходство между точками. Как это определяет сходство? Во-первых, оно определяется евклидовым расстоянием между точкамиXiа такжеXj, Во-вторых, это определяется как условная вероятность того, что «сходство точек данныхяВ точкуJэто условная вероятностьпэтот моментявыбрал бы данныеJв качестве соседа, если другие соседи были выбраны в соответствии с их вероятностями при гауссовском распределении ». В следующем условном выражении if pointJближе к точкеячем другие пункты, у него есть более высокая вероятность (заметьте отрицательный знак) быть выбранным

t-SNE стремится соответствовать вышеуказанной условной вероятностипмеждуJа такжеякак можно более низкоразмерным пространствомQмежду точкойYiа такжеYj,как показано ниже. ВероятностьQследует распределению Student-t с толстым хвостом, таким образом,T»В T-SNE происходит от.

Следующий шаг - найтиYiтакой, что распределениеQбудет как можно ближе к распределениюпнасколько это возможно. t-SNE использует метод градиентного приличия, метод оптимизации, чтобы найти значения.

Ниже я продемонстрирую, как метод t-SNE используется с набором данных радужной оболочки.

from sklearn.manifold import TSNE
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
iris = load_iris()
X_tsne = TSNE(learning_rate=100).fit_transform(iris.data)
X_pca = PCA().fit_transform(iris.data)
plt.figure(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)

Для получения дополнительной информации, этот пост «как более эффективно использовать t-SNE»Предоставляет больше обсуждений.

Оригинальная статья

Footer decor

© machinelearningmastery.ru | Ссылки на оригиналы и авторов сохранены. | map