www.machinelearningmastery.ru

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

Home

Линейный дискриминантный анализ в Python

Дата публикации Aug 4, 2019

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

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

Это плохо, потому что игнорирует любую полезную информацию, предоставляемую второй функцией. С другой стороны, Линейный Дискриминантный Анализ, или LDA, использует информацию обеих функций для создания новой оси и проецирует данные на новую ось таким образом, чтобы минимизировать дисперсию и максимизировать расстояние между средними значениями. два класса.

Код

Давайте посмотрим, как мы можем реализовать линейный дискриминантный анализ с нуля с использованием Python. Для начала импортируйте следующие библиотеки.

from sklearn.datasets import load_wine
import pandas as pd
import numpy as np
np.set_printoptions(precision=4)
from matplotlib import pyplot as plt
import seaborn as sns
sns.set()
from sklearn.preprocessing import LabelEncoder
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix

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

wine = load_wine()X = pd.DataFrame(wine.data, columns=wine.feature_names)
y = pd.Categorical.from_codes(wine.target, wine.target_names)

Набор данных содержит 178 строк по 13 столбцов в каждой.

X.shape

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

X.head()

Есть 3 разных вида вина.

wine.target_names

Мы создаем DataFrame, содержащий как функции, так и классы.

df = X.join(pd.Series(y, name='class'))

Линейный Дискриминантный Анализможно разбить на следующие шаги:

  1. Вычислить внутри класса и между матрицами рассеяния класса
  2. Вычислить собственные векторы и соответствующие собственные значения для матриц рассеяния
  3. Сортировать собственные значения и выбрать верхК
  4. Создайте новую матрицу, содержащую собственные векторы, которые отображаются наКсобственные
  5. Получите новые функции (т.е. компоненты LDA), взяв точечное произведение данных и матрицы из шага 4

Внутри матрицы рассеяния классов

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

гдесэто общее количество отдельных классов и

гдеИксэто образец (то есть строка) иNобщее количество образцов с данным классом.

Для каждого класса мы создаем вектор со средствами каждого объекта.

class_feature_means = pd.DataFrame(columns=wine.target_names)for c, rows in df.groupby('class'):
class_feature_means[c] = rows.mean()class_feature_means

Затем мы вставляем средние векторы (ми) в уравнение, чтобы получить матрицу рассеяния внутри класса.

within_class_scatter_matrix = np.zeros((13,13))for c, rows in df.groupby('class'):rows = rows.drop(['class'], axis=1)

s = np.zeros((13,13))for index, row in rows.iterrows():
x, mc = row.values.reshape(13,1), class_feature_means[c].values.reshape(13,1)

s += (x - mc).dot((x - mc).T)

within_class_scatter_matrix += s

Матрица рассеяния между классами

Далее рассчитаеммежду матрицей рассеяния классовиспользуя следующую формулу.

где

feature_means = df.mean()between_class_scatter_matrix = np.zeros((13,13))for c in class_feature_means:    
n = len(df.loc[df['class'] == c].index)

mc, m = class_feature_means[c].values.reshape(13,1), feature_means.values.reshape(13,1)

between_class_scatter_matrix += n * (mc - m).dot((mc - m).T)

Затем мы решаем обобщенную проблему собственных значений для

получить линейные дискриминанты.

eigen_values, eigen_vectors = np.linalg.eig(np.linalg.inv(within_class_scatter_matrix).dot(between_class_scatter_matrix))

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

pairs = [(np.abs(eigen_values[i]), eigen_vectors[:,i]) for i in range(len(eigen_values))]pairs = sorted(pairs, key=lambda x: x[0], reverse=True)for pair in pairs:
print(pair[0])

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

eigen_value_sums = sum(eigen_values)print('Explained Variance')
for i, pair in enumerate(pairs):
print('Eigenvector {}: {}'.format(i, (pair[0]/eigen_value_sums).real))

Сначала мы создаем матрицуWс первыми двумя собственными векторами.

w_matrix = np.hstack((pairs[0][1].reshape(13,1), pairs[1][1].reshape(13,1))).real

Затем мы сохраняем скалярное произведениеИкса такжеWв новую матрицуY,

гдеИксэтоп × дматрица сNобразцы иdразмеры иYэтоп × кматрица сNобразцы иК(k <n) размеры. Другими словами,Yсостоит из компонентов LDA или, иначе говоря, нового пространства функций.

X_lda = np.array(X.dot(w_matrix))

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

le = LabelEncoder()y = le.fit_transform(df['class'])

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

plt.xlabel('LD1')
plt.ylabel('LD2')plt.scatter(
X_lda[:,0],
X_lda[:,1],
c=y,
cmap='rainbow',
alpha=0.7,
edgecolors='b'
)

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

from sklearn.discriminant_analysis import LinearDiscriminantAnalysislda = LinearDiscriminantAnalysis()X_lda = lda.fit_transform(X, y)

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

lda.explained_variance_ratio_

Как и раньше, мы строим два компонента LDA.

plt.xlabel('LD1')
plt.ylabel('LD2')plt.scatter(
X_lda[:,0],
X_lda[:,1],
c=y,
cmap='rainbow',
alpha=0.7,
edgecolors='b'
)

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

from sklearn.decomposition import PCApca = PCA(n_components=2)X_pca = pca.fit_transform(X, y)

Мы можем получить доступ кexplained_variance_ratio_свойство, чтобы просмотреть процент дисперсии, объясненной каждым компонентом.

pca.explained_variance_ratio_

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

plt.xlabel('PC1')
plt.ylabel('PC2')plt.scatter(
X_pca[:,0],
X_pca[:,1],
c=y,
cmap='rainbow',
alpha=0.7,
edgecolors='b'
)

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

X_train, X_test, y_train, y_test = train_test_split(X_lda, y, random_state=1)

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

dt = DecisionTreeClassifier()dt.fit(X_train, y_train)y_pred = dt.predict(X_test)confusion_matrix(y_test, y_pred)

Как мы видим, классификатор дерева решений правильно классифицировал все в тестовом наборе.

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

Footer decor

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