Привет, в этом посте я собираюсь объяснить, как методы уменьшения размерности влияют на модель прогнозирования. Здесь мы используем набор данных Iris и классификатор K-NN. Мы собираемся сравнить PCA и LDA на наборе данных Iris.
Прежде чем приступить к экспериментам, лучше бы освежить в памяти концепции PCA и LDA. Поэтому я постараюсь объяснить их короткими заметками. Начнем с PCA.
Анализ главных компонентов (PCA)
PCA - это статистический инструмент, часто используемый для уменьшения размерности. Это помогает преобразовать данные с более высокой размерностью в данные с более низкой размерностью, прежде чем применять какую-либо модель машинного обучения. Это алгоритм обучения без учителя. Позвольте мне начать с объяснения того, что делает PCA. На изображении ниже мы видим объект сверху, снизу и сбоку. Обратите внимание, что объект может иметь 360 просмотров. Если эта кружка (объект) является данными, то PCA помогает нам найти виды (направления), где видна самая большая часть чашки. Например, если есть только вид сбоку и снизу, PCA дает нам вид сбоку, потому что видна большая площадь чая. Здесь вид сбоку рассматривается как первая основная составляющая. Получив первый главный компонент, мы вращаем чашу в направлениях, перпендикулярных первому главному компоненту. Направление, которое охватывает самую большую часть и перпендикулярно первому главному компоненту, называется вторым главным компонентом. Таким образом мы можем найти третий, четвертый и так далее.
Шаги для выполнения PCA:
Нормализуйте данные и найдите матрицу ковариации. Затем найдите собственные векторы и соответствующие собственные значения. Первый главный компонент - это не что иное, как собственный вектор с наибольшим собственным значением и так далее.
Линейный дискриминантный анализ (LDA):
LDA - это метод контролируемого уменьшения размерности. Он делает предположения на основе данных. Это обобщение линейного дискриминанта Фишера. LDA не находит основных компонентов. Вместо этого он увеличивает межклассовое расстояние и уменьшает внутриклассовое расстояние. Подробное описание LDA можно найти здесь.
Загрузите необходимые библиотеки
from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from tqdm import tqdm import numpy as np import pandas as pd import matplotlib.pyplot as plt %matplotlib inline import seaborn as sn from sklearn.metrics.pairwise import euclidean_distances import warnings warnings.filterwarnings("ignore")
Загрузите данные IRIS и выполните стандартизацию
dataset = pd.read_csv('iris.csv') #read the data into dataframe X = dataset.iloc[:, :-1].values #store the dependent features in X y = dataset.iloc[:, 4].values #store the independent variable in y X = StandardScaler().fit_transform(X)
Выполните PCA и визуализируйте данные
# initializing the pca from sklearn import decomposition pca = decomposition.PCA() # configuring the parameteres # the number of components = 2 # we have taken only 2 components as it is easy to visualize pca.n_components = 2 # pca_reduced will contain the 2-d projects of simple data pca_data = pca.fit_transform(X) print("shape of pca_reduced.shape = ", pca_data.shape) #>>> shape of pca_reduced.shape = (150, 2) # attaching the label for each 2-d data point pca_data = np.vstack((pca_data.T, y)).T # creating a new data from which help us in ploting the result data pca_df = pd.DataFrame(data=pca_data, columns=("1st_principal", "2nd_principal", "label")) sn.FacetGrid(pca_df, hue="label", size=4).map(plt.scatter, '1st_principal', '2nd_principal').add_legend() plt.show()
Построение графика зависимости количества основных компонентов от максимальной кумулятивной дисперсии
# PCA for dimensionality redcution (not-visualization) pca.n_components = 4 pca_data = pca.fit_transform(X) percentage_var_explained = pca.explained_variance_ / np.sum(pca.explained_variance_) cum_var_explained = np.cumsum(percentage_var_explained) # Plot the PCA spectrum plt.figure(1, figsize=(6, 4)) plt.xticks(np.arange(0, 4, step=1),(1,2,3,4)) plt.plot(cum_var_explained, linewidth=2) plt.axis('tight') plt.grid() plt.xlabel('n_components') plt.ylabel('Cumulative_explained_variance') plt.show()
Если взять 1-мерное, прибл. 72% расхождения объясняются, а если взять 2-х мерную величину, прибл. Объяснено 95% отклонений.
Выполните LDA и визуализируйте данные
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis lda = LinearDiscriminantAnalysis(n_components=2) lda_data = lda.fit(X, y).transform(X) # attaching the label for each 2-d data point lda_data = np.vstack((lda_data.T, y)).T # creating a new data fram which help us in ploting the result data lda_df = pd.DataFrame(data=lda_data, columns=("1st_principal", "2nd_principal", "label")) sn.FacetGrid(lda_df, hue="label", size=4).map(plt.scatter, '1st_principal', '2nd_principal').add_legend() plt.show()
Применение K-NN к исходным ДАННЫМ IRIS
def divide_training_dataset_to_k_folds(x_train,y_train,folds): temp = len(x_train)/folds x_train = x_train.tolist() y_train = y_train.tolist() group = [] label = [] end = 0.0 while end < len(x_train): group.append(x_train[int(end):int(end + temp)]) label.append(y_train[int(end):int(end + temp)]) end += temp return group,label
Определите метод случайной перекрестной проверки:
from sklearn.metrics import accuracy_score def RandomSearchCV(x_train,y_train,classifier, param_range, folds): # x_train: its numpy array of shape, (n,d) # y_train: its numpy array of shape, (n,) or (n,1) # classifier: its typically KNeighborsClassifier() # param_range: its a tuple like (a,b) a < b # folds: an integer, represents number of folds we need to devide the data and test our model params = list(range(1,51)) #1.divide numbers ranging from 0 to len(X_train) into groups= folds # ex: folds=3, and len(x_train)=100, we can devide numbers from 0 to 100 into 3 groups i.e: group 1: 0-33, group 2:34-66, group 3: 67-100 temp = len(x_train)/folds temp = int(temp) groups,labels = divide_training_dataset_to_k_folds(x_train,y_train, folds) #2.for each hyperparameter that we generated in step 1 and using the above groups we have created in step 2 you will do cross-validation as follows: # first we will keep group 1+group 2 i.e. 0-66 as train data and group 3: 67-100 as test data, and find train and test accuracies # second we will keep group 1+group 3 i.e. 0-33, 67-100 as train data and group 2: 34-66 as test data, and find train and test accuracies # third we will keep group 2+group 3 i.e. 34-100 as train data and group 1: 0-33 as test data, and find train and test accuracies # based on the 'folds' value we will do the same procedure # find the mean of train accuracies of above 3 steps and store in a list "train_scores" # find the mean of test accuracies of above 3 steps and store in a list "test_scores" train_scores = [] test_scores = [] for k in tqdm(params): trainscores_folds = [] testscores_folds = [] for i in range(folds): X_train = [groups[iter] for iter in range(folds) if iter != i] X_train = [j for sublist in X_train for j in sublist] Y_train = [labels[iter] for iter in range(folds) if iter != i] Y_train = [j for sublist in Y_train for j in sublist] X_test = groups[i] Y_test = labels[i] classifier.n_neighbors = k classifier.fit(X_train,Y_train) Y_predicted = classifier.predict(X_test) testscores_folds.append(accuracy_score(Y_test, Y_predicted)) Y_predicted = classifier.predict(X_train) trainscores_folds.append(accuracy_score(Y_train, Y_predicted)) train_scores.append(np.mean(np.array(trainscores_folds))) test_scores.append(np.mean(np.array(testscores_folds))) #3. return both "train_scores" and "test_scores" return train_scores, test_scores,params
Классификатор К НН
from sklearn.metrics import accuracy_score from sklearn.neighbors import KNeighborsClassifier import matplotlib.pyplot as plt classifier = KNeighborsClassifier() param_range = (1,50) folds = 3 X = dataset.iloc[:, :-1].values#store the dependent features in X y = dataset.iloc[:, 4].values #store the independent variable in y X_train, X_test, y_train, y_test = train_test_split(X, y,stratify=y, random_state=42,test_size=0.30) trainscores,testscores,params=RandomSearchCV(X_train,y_train,classifier, param_range, folds) # plot hyper-parameter vs accuracy plot as shown in reference notebook and choose the best hyperparameter plt.plot(params,trainscores, label='train curve') plt.plot(params,testscores, label='test curve') plt.title('Hyper-parameter VS accuracy plot') plt.legend() plt.show()
Применение K-NN к модифицированным данным IRIS с использованием PCA
X = pca_df.iloc[:, :-1].values#store all the dependent features in X y = pca_df.iloc[:, -1].values #store the independent variable in y X_train, X_test, y_train, y_test = train_test_split(X, y,stratify=y, random_state=42,test_size=0.30) #training data = 70% and test data = 30% trainscores,testscores,params=RandomSearchCV(X_train,y_train,classifier, param_range, folds) # plot hyper-parameter vs accuracy plot as shown in reference notebook and choose the best hyperparameter plt.plot(params,trainscores, label='train curve') plt.plot(params,testscores, label='test curve') plt.title('Hyper-parameter VS accuracy plot') plt.legend() plt.show()
Применение K-NN к модифицированным данным IRIS с использованием LDA
X_train, X_test, y_train, y_test = train_test_split(X,y,stratify=y, random_state=42,test_size=0.30) trainscores,testscores,params=RandomSearchCV(X_train,y_train,classifier, param_range, folds) # plot hyper-parameter vs accuracy plot as shown in reference notebook and choose the best hyperparameter plt.plot(params,trainscores, label='train curve') plt.plot(params,testscores, label='test curve') plt.title('Hyper-parameter VS accuracy plot') plt.legend() plt.show()
Вывод:
Подводя итог, мы можем наблюдать из приведенных выше результатов, что PCA плохо работает с помеченными данными. С другой стороны, LDA не снизило производительность модели KNN, а также уменьшило сложность набора данных. Поскольку PCA является неконтролируемым методом, он не принимает во внимание метки классов. Таким образом, мы можем сделать вывод, что LDA - лучший метод уменьшения размерности, чем PCA для помеченных данных.
Ссылка для кода: github
Примечание: сокращенный набор данных с использованием LDA дал ту же точность, что и исходный набор данных, то есть 97%. Однако сокращенный набор данных с использованием PCA дал точность 91%, что очень мало !!!