#!/usr/bin/env python
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.decomposition import PCA
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA

# Import different modules for using with the notebook
from IPython.display import display
from IPython.display import Image
from IPython.display import HTML

from printdescribe import print2

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.naive_bayes import GaussianNB, CategoricalNB
from sklearn.ensemble import RandomForestClassifier

from sklearn import metrics
from sklearn.datasets import load_wine
from sklearn.pipeline import make_pipeline
print(__doc__)


RANDOMSTATE = 42
FIGSIZE = (12, 8)
show = plt.show()

# features, targets = load_wine(return_X_y=True)

# download the data
wine = datasets.load_wine()

features = wine.data
targets = wine.target
labelnames = wine.target_names

# create train/test split using 25% test size
X_train, X_test, y_train, y_test = train_test_split(features, targets,
                                                    test_size=0.30,
                                                    random_state=RANDOMSTATE)                                             

# define colors and markers
markers = ["*","o", "+"]
colors = ["r", "y", "k"]
col = ['r*','yo','k+']
labels = y_test

# Fit to data and predict using pipelined scaling, PCA.
pca = make_pipeline(StandardScaler(), PCA(n_components=2))
pca.fit(X_train)
pca_result = pca.transform(X_test)

# plot
for i, label in enumerate(np.unique(y_test)):
    plt.plot(pca_result[:,0][labels==label],pca_result[:,1][labels==label], 
                col[int(i)], label=labelnames[i])
plt.title("The projection onto 2 PCA components")
plt.legend(loc='best', shadow=False, scatterpoints=3)
plt.show();


# Fit to data and predict using pipelined scaling, LDA.
lda = LDA(n_components=2)
lda.fit(X_train,y_train)
lda_result = lda.transform(X_test)

# plot
for i, label in enumerate(np.unique(y_test)):
    plt.scatter(lda_result[:,0][y_test==label],lda_result[:,1][y_test==label], 
                c=colors[i], marker=markers[i], lw=1, label=labelnames[i])
plt.title("The projection onto 2 LDA components with scaling")
plt.legend(loc='best', shadow=False, scatterpoints=3)
plt.show();


# Fit to data and predict without using pipelined scaling, LDA.
lda2 = LDA(n_components=2)
lda2.fit(X_train,y_train)
lda_result = lda2.transform(X_test)

# plot
for i, label in enumerate(np.unique(y_test)):
    plt.scatter(lda_result[:,0][y_test==label],lda_result[:,1][y_test==label], 
                c=colors[i], marker=markers[i], lw=1, label=labelnames[i])
plt.title("The projection onto 2 LDA components without scaling")
plt.legend(loc='best', shadow=False, scatterpoints=3)
show;


############################################################################################################
############################################################################################################

features, target = load_wine(return_X_y=True)

# Make a train/test split using 30% test size
X_train, X_test, y_train, y_test = train_test_split(features, target,
                                                    test_size=0.30,
                                                    random_state=RANDOMSTATE)

# Fit to data and predict using pipelined GNB and PCA.
unscaled_clf = make_pipeline(PCA(n_components=2), GaussianNB())
unscaled_clf.fit(X_train, y_train)
pred_test = unscaled_clf.predict(X_test)

# Fit to data and predict using pipelined scaling, GNB and PCA.
std_clf = make_pipeline(StandardScaler(), PCA(n_components=2), GaussianNB())
std_clf.fit(X_train, y_train)
pred_test_std = std_clf.predict(X_test)

# Show prediction accuracies in scaled and unscaled data.
print('\nPrediction accuracy for the normal test dataset with PCA')
print('{:.2%}\n'.format(metrics.accuracy_score(y_test, pred_test)))

print('\nPrediction accuracy for the standardized test dataset with PCA')
print('{:.2%}\n'.format(metrics.accuracy_score(y_test, pred_test_std)))

# Extract PCA from pipeline
pca = unscaled_clf.named_steps['pca']
pca_std = std_clf.named_steps['pca']

# Show first principal components
print('\nPC 1 without scaling:\n', pca.components_[0])
print('\nPC 1 with scaling:\n', pca_std.components_[0])

# Use PCA without and with scale on X_train data for visualization.
X_train_transformed = pca.transform(X_train)
scaler = std_clf.named_steps['standardscaler']
X_train_std_transformed = pca_std.transform(scaler.transform(X_train))

# visualize standardized vs. untouched dataset with PCA performed
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=FIGSIZE)


for l, c, m in zip(range(0, 3), ('blue', 'red', 'green'), ('^', 's', 'o')):
    ax1.scatter(X_train_transformed[y_train == l, 0],
                X_train_transformed[y_train == l, 1],
                color=c,
                label='class %s' % l,
                alpha=0.5,
                marker=m
                )

for l, c, m in zip(range(0, 3), ('blue', 'red', 'green'), ('^', 's', 'o')):
    ax2.scatter(X_train_std_transformed[y_train == l, 0],
                X_train_std_transformed[y_train == l, 1],
                color=c,
                label='class %s' % l,
                alpha=0.5,
                marker=m
                )

ax1.set_title('Training dataset after PCA')
ax2.set_title('Standardized training dataset after PCA')

for ax in (ax1, ax2):
    ax.set_xlabel('1st principal component')
    ax.set_ylabel('2nd principal component')
    ax.legend(loc='upper right')
    ax.grid()

plt.tight_layout()

plt.show()


# Fit to data and predict using pipelined RandomForestClassifier and PCA.
unscaled_clf = make_pipeline(RandomForestClassifier())
unscaled_clf.fit(X_train, y_train)
pred_test = unscaled_clf.predict(X_test)

# Fit to data and predict using pipelined scaling, RandomForestClassifier and PCA.
std_clf = make_pipeline(StandardScaler(), RandomForestClassifier())
std_clf.fit(X_train, y_train)
pred_test_std = std_clf.predict(X_test)

# Show prediction accuracies in scaled and unscaled data.
print('\nPrediction accuracy for the normal test dataset with PCA')
print('{:.2%}\n'.format(metrics.accuracy_score(y_test, pred_test)))

print('\nPrediction accuracy for the standardized test dataset with PCA')
print('{:.2%}\n'.format(metrics.accuracy_score(y_test, pred_test_std)))
