머신러닝

붓꽃 데이터 LDA 처리 후 Classification

coding art 2019. 5. 31. 14:14
728x90


2개의 LD(Linear Discriminant)가 결정되고 이에 따라 작도가 이루어졌다. LDA기법에서의 Classification 이란 결정된 LD 축을 따른 분포를 고려하는 것이다. 아래 그림을 보면 eigenvalue 의 큰 값에 해당하는 LD1 축을 따라서 Classification 이 가능하다는 것을 알 수 있다. eigenvalue 가 가장 클 때에 가장 informative 하다는 점을 알 수 있다.




LDA 오픈 소스를 사용하여 차원이 4인 붓꽃 데이터를 차원이 2인 데이터로 변환하였으며 아래 그림의 오른쪽 편이 그 결과이다. 오픈소스란 eigenvalue 계산까지 이르는 과정을 각론으로 쪼개어 기술했던 #iris_lda_Classifiers_01.py 코드를 의미한다. 반면에 scikit-learn 라이브러리에서 제공하는 LDA 전용 명령을 사용하면 왼쪽 그림의 결과가 얻어진다. 양 그래프의 패턴 자체는 동일하나 LD1, LD2 의 스케일이 다르다.



 

아래는 LDA 오픈소스인 Iris_lda_Classifiers_01.py 코드에서 각론으로 들어 있는 꽤 긴 분량의 LDA 과정이 하나의 LDA 전용 명령으로 대체되는 부분이다. 물론 입력 데이터를 준비하는 부분은 그대로 활용이 된다.



아울러 특기할 점은 LDA 명령에서 n_components=2로 설정하는데 사실 변환 작업 해보기 전에는 유효 eigenvalue 2개가 나올지 3개가 나올지 알 수 없는데 미리 2개로 설정한다는 점이다. 실제 코드에서 n_components=3으로 두고 코드를 실행해도 동일한 결과를 생성한다. LDA에서는 eigenvalue 가 원래 있는 만큼 계산되므로 아무런 문제가 되지 않는다.

 

아울러 이미 LDA에 의해서 데이터가 상당히 잘 분류되었기 때문에 LDA+Classifiers 처리과정에 의해서도 모두 100%의 정확도를 확인할 수 있다.

 

#iris_sklearn_lda_Classifiers_01.py

import pandas as pd
from matplotlib import pyplot as plt
import numpy as np
import math

s1 = 'sepal length cm'
s2 = 'sepal width cm'
s3 = 'petal length cm'
s4 = 'petal width cm'

feature_dict = {i:label for i,label in zip(range(4),( s1, s2, s3, s4))}

df = pd.io.parsers.read_csv(filepath_or_buffer=
    'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data',
    header=None,sep=',',)
df.columns = [l for i,l in sorted(feature_dict.items())] + ['class label']
df.dropna(how="all", inplace=True) # to drop the empty line at file-end

df.tail()

from sklearn.preprocessing import LabelEncoder

X=df[[ s1, s2, s3, s4]].values
y = df['class label'].values

enc = LabelEncoder()
label_encoder = enc.fit(y)
y = label_encoder.transform(y) + 1

label_dict = {1: 'Setosa', 2: 'Versicolor', 3:'Virginica'}


from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA

# LDA
sklearn_lda = LDA(n_components=2)
X_lda_sklearn = sklearn_lda.fit_transform(X, y)
print(X_lda_sklearn)

def plot_scikit_lda(X, title):

    ax = plt.subplot(111)
    for label,marker,color in zip(
        range(1,4),('^', 's', 'o'),('blue', 'red', 'green')):

        plt.scatter(x=X[:,0][y == label],
                    y=X[:,1][y == label] * -1, #flip the figure
                    marker=marker,
                    color=color,
                    alpha=0.5,
                    label=label_dict[label])

    plt.xlabel('LD1')
    plt.ylabel('LD2')

    leg = plt.legend(loc='upper right', fancybox=True)
    leg.get_frame().set_alpha(0.5)
    plt.title(title)

    #hide axis ticks
    plt.tick_params(axis="both", which="both", bottom="off", top="off", 
            labelbottom=on", left="off", right="off", labelleft=on")

    #remove axis spines
    ax.spines["top"].set_visible(False) 
    ax.spines["right"].set_visible(False)
    ax.spines["bottom"].set_visible(False)
    ax.spines["left"].set_visible(False)   

    plt.grid()
    plt.tight_layout
    plt.show()

plot_scikit_lda(X_lda_sklearn, title='Default LDA via scikit-learn')


#
print('Class labels:', np.unique(y))

from sklearn.model_selection import train_test_split

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


print('Labels counts in y:', np.bincount(y))
print('Labels counts in y_train:', np.bincount(y_train))
print('Labels counts in y_test:', np.bincount(y_test))

from sklearn.preprocessing import StandardScaler

sc = StandardScaler()
sc.fit(X_train)
X_train_std = sc.transform(X_train)
X_test_std = sc.transform(X_test)

# ## Training a perceptron via scikit-learn

from sklearn.linear_model import Perceptron
from sklearn.metrics import accuracy_score

ppn = Perceptron(n_iter=50, eta0=0.1, random_state=1)
ppn.fit(X_train_std, y_train)

y_pred = ppn.predict(X_test_std)
print('\nLDA+Perceptron')
print('Misclassified samples: %d' % (y_test != y_pred).sum())
print('Accuracy: %.2f' % accuracy_score(y_test, y_pred))
print('Accuracy: %.2f' % ppn.score(X_test_std, y_test))


from matplotlib.colors import ListedColormap
import matplotlib.pyplot as plt

def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02):

    # setup marker generator and color map
    markers = ('s', 'x', 'o', '^', 'v')
    colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
    cmap = ListedColormap(colors[:len(np.unique(y))])

    # plot the decision surface
    x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
                           np.arange(x2_min, x2_max, resolution))
    Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
    Z = Z.reshape(xx1.shape)
    plt.contourf(xx1, xx2, Z, alpha=0.3, cmap=cmap)
    plt.xlim(xx1.min(), xx1.max())
    plt.ylim(xx2.min(), xx2.max())

    for idx, cl in enumerate(np.unique(y)):
        plt.scatter(x=X[y == cl, 0],
                    y=X[y == cl, 1],
                    alpha=0.8,
                    c=colors[idx],
                    marker=markers[idx],
                    label=cl,
                    edgecolor='black')

    # highlight test samples
    if test_idx:
        # plot all samples
        X_test, y_test = X[test_idx, :], y[test_idx]

        plt.scatter(X_test[:, 0],
                    X_test[:, 1],
                    c='',
                    edgecolor='black',
                    alpha=1.0,
                    linewidth=1,
                    marker='o',
                    s=100,
                    label='test set')


# Training a perceptron model using the standardized training data:
X_combined_std = np.vstack((X_train_std, X_test_std))
y_combined = np.hstack((y_train, y_test))

plot_decision_regions(X=X_combined_std, y=y_combined,
                      classifier=ppn, test_idx=range(105, 150))
plt.xlabel('petal length [standardized]')
plt.ylabel('petal width [standardized]')
plt.legend(loc='upper left')

plt.tight_layout()
plt.show()


# Training a LogisticRegression model using the standardized training data:
from sklearn.linear_model import LogisticRegression

X_combined_std = np.vstack((X_train_std, X_test_std))
y_combined = np.hstack((y_train, y_test))

lr = LogisticRegression(C=100.0, random_state=1)
lr.fit(X_train_std, y_train)

y_pred = lr.predict(X_test_std)
print('\nLDA+LogisticRegression: C=100.0: OvR')
print('Misclassified samples: %d' % (y_test != y_pred).sum())
print('Accuracy: %.2f' % accuracy_score(y_test, y_pred))
print('Accuracy: %.2f' % lr.score(X_test_std, y_test))

plot_decision_regions(X=X_combined_std, y=y_combined,
                      classifier=lr, test_idx=range(105, 150))
plt.xlabel('petal length [standardized]')
plt.ylabel('petal width [standardized]')
plt.legend(loc='upper left')
plt.show()

from sklearn.svm import SVC

#C=1.0 OK  'linear'
svm = SVC(kernel='linear', C=1.0, random_state=1)
svm.fit(X_train_std, y_train)
y_pred = svm.predict(X_test_std)

print('\nLDA+Support Vector Machine SVM(linear): C=100.0')
print('Misclassified samples: %d' % (y_test != y_pred).sum())
print('Accuracy: %.2f' % accuracy_score(y_test, y_pred))
print('Accuracy: %.2f' % svm.score(X_test_std, y_test))

plot_decision_regions(X_combined_std,
                      y_combined,
                      classifier=svm,
                      test_idx=range(105, 150))
plt.xlabel('petal length [standardized]')
plt.ylabel('petal width [standardized]')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()


#C=1.0, 10.0, 100.0 OK  'RBF'
svm = SVC(kernel='rbf', random_state=1, gamma=0.2, C=100.0)
svm.fit(X_train_std, y_train)

y_pred = svm.predict(X_test_std)
print('\nLDA+Support Vector Machine SVM(RBF): gamma=0.2,C=100.0')
print('Misclassified samples: %d' % (y_test != y_pred).sum())
print('Accuracy: %.2f' % accuracy_score(y_test, y_pred))
print('Accuracy: %.2f' % svm.score(X_test_std, y_test))

plot_decision_regions(X_combined_std, y_combined,
                      classifier=svm, test_idx=range(105, 150))
plt.xlabel('petal length [standardized]')
plt.ylabel('petal width [standardized]')
plt.legend(loc='upper left')
plt.show()


from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
from sklearn.tree import export_graphviz

tree = DecisionTreeClassifier(criterion='gini',
                              max_depth=None,
                              random_state=1)
tree.fit(X_train, y_train)
y_pred = tree.predict(X_test)
print('\nLDA+Decision Tree')
print('Misclassified samples: %d' % (y_test != y_pred).sum())
print('Accuracy: %.2f' % accuracy_score(y_test, y_pred))
print('Accuracy: %.2f' % tree.score(X_test, y_test))

X_combined = np.vstack((X_train, X_test))
y_combined = np.hstack((y_train, y_test))
plot_decision_regions(X_combined, y_combined,
                      classifier=tree, test_idx=range(105, 150))

plt.xlabel('petal length [cm]')
plt.ylabel('petal width [cm]')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()


forest = RandomForestClassifier(criterion='gini',
                                n_estimators=25,
                                random_state=1,
                                n_jobs=2)
forest.fit(X_train, y_train)
y_pred = forest.predict(X_test)
print('\nLDA+Random Forests')
print('Misclassified samples: %d' % (y_test != y_pred).sum())
print('Accuracy: %.2f' % accuracy_score(y_test, y_pred))
print('Accuracy: %.2f' % forest.score(X_test, y_test))

plot_decision_regions(X_combined, y_combined,
                      classifier=forest, test_idx=range(105, 150))

plt.xlabel('petal length [cm]')
plt.ylabel('petal width [cm]')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()