"""
# Exercice : Zalando Fashion MNIST
"""
"""
## Librairies et fonctions utiles
"""
# Pandas : librairie de manipulation de données
# NumPy : librairie de calcul scientifique
# MatPlotLib : librairie de visualisation et graphiques
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
import seaborn as sns

from sklearn import model_selection
from sklearn.metrics import classification_report, confusion_matrix, roc_curve, roc_auc_score,auc, accuracy_score
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn import datasets
"""
Fonction pour tracer les courbes d'apprentissage sur l'ensemble d'apprentissage et l'ensemble de validation :
"""
from sklearn.model_selection import learning_curve
def plot_learning_curve(est, X_train, y_train) :
    train_sizes, train_scores, test_scores = learning_curve(estimator=est, X=X_train, y=y_train, train_sizes=np.linspace(0.1, 1.0, 10),
                                                        cv=5,
                                                        n_jobs=-1)
    train_mean = np.mean(train_scores, axis=1)
    train_std = np.std(train_scores, axis=1)
    test_mean = np.mean(test_scores, axis=1)
    test_std = np.std(test_scores, axis=1)
    plt.figure(figsize=(8,10))
    plt.plot(train_sizes, train_mean, color='blue', marker='o', markersize=5, label='training accuracy')
    plt.fill_between(train_sizes, train_mean + train_std, train_mean - train_std, alpha=0.15, color='blue')
    plt.plot(train_sizes, test_mean,color='green', linestyle='--',marker='s', markersize=5,label='validation accuracy')
    plt.fill_between(train_sizes,test_mean + test_std,test_mean - test_std,alpha=0.15, color='green')
    plt.grid(b='on')
    plt.xlabel('Number of training samples')
    plt.ylabel('Accuracy')
    plt.legend(loc='lower right')
    plt.ylim([0.6, 1.0])
    plt.show()
"""
Fonction pour tracer la courbe ROC :
"""
def plot_roc_curve(est,X_test,y_test) :
    probas = est.predict_proba(X_test)
    false_positive_rate, true_positive_rate, thresholds = roc_curve(y_test,probas[:, 1])
    roc_auc = auc(false_positive_rate, true_positive_rate)
    plt.figure(figsize=(8,8))
    plt.title('Receiver Operating Characteristic')
    plt.plot(false_positive_rate, true_positive_rate, 'b', label='AUC = %0.2f'% roc_auc)
    plt.legend(loc='lower right')
    plt.plot([0,1],[0,1],'r--')        # plus mauvaise courbe
    plt.plot([0,0,1],[0,1,1],'g:')     # meilleure courbe
    plt.xlim([-0.05,1.2])
    plt.ylim([-0.05,1.2])
    plt.ylabel('Taux de vrais positifs')
    plt.xlabel('Taux de faux positifs')
    plt.show
"""
## Zalando Fashion MNIST
"""
"""
Le dataset a été constitué par Zalando :  
https://github.com/zalandoresearch/fashion-mnist  
  
On a un ensemble d'apprentissage de 60 000 images 28x28 pixels en niveaux de gris, et 10 classes de vêtements : jupes, pantalons, baskets, ...
"""
"""
<img src="https://github.com/zalandoresearch/fashion-mnist/blob/master/doc/img/fashion-mnist-sprite.png?raw=true">
"""
df = pd.read_csv('../input/fashionmnist/fashion-mnist_train.csv')
df.head()
labels = ["T-shirt/top","Trouser","Pullover","Dress","Coat","Sandal","Shirt",
          "Sneaker","Bag","Ankle boot"]
"""
La première image du dataset est un pull :
"""
print(labels[df.label[0]])
"""
**Afficher les 50 premiers éléments du dataset avec leur label**  

"""
df.shape
df.head()
y = df['label']
X = df.drop(['label'], axis=1)
X1 = np.array(X)
image = X1[0].reshape(28,28)
plt.imshow(image)
plt.imshow(image, cmap="gray_r")
plt.axis('off')
plt.title(labels[y[0]])
n_samples = len(df.index)
images = X1.reshape(n_samples,28,28)
plt.figure(figsize = (10,20))
for i in range(0,50) :
    plt.subplot(10,5,i+1)
    plt.axis('off')
    plt.imshow(images[i], cmap="gray_r")
    plt.title(labels[y[i]])
"""
# *Réseaux denses (sklearn)*
"""
# On normalise les valeurs entre 0 et 1
X = X/225
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 1)
"""
On utilise la méthode *MLPClassifier* de *sklearn* pour utiliser un réseau de neurones à deux couches cachées de 200 et 60 neurones :
"""
from sklearn.neural_network import MLPClassifier
mlp = MLPClassifier(hidden_layer_sizes = (200,60))
mlp.fit(X_train,y_train)
y_mlp = mlp.predict(X_test)
mlp_score = accuracy_score(y_test, y_mlp)
print(mlp_score)
pd.crosstab(y_test, y_mlp, rownames=['Reel'], colnames=['Prediction'], margins=True)
"""
# *Réseaux denses (Keras/Tensorflow)*
"""
from keras.utils.np_utils import to_categorical
print(y[0])
y_cat = to_categorical(y)
print(y_cat[0])
"""
On a seulement X classes  :
"""
num_classes = y_cat.shape[1]
print(num_classes)
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y_cat, test_size=0.2, random_state=1)
"""
Pour Keras, il est nécessaire d'avoir des tableaux et non des dataframes :
"""
X_train = np.array(X_train)
X_test = np.array(X_test)
y_train = np.array(y_train)
y_test = np.array(y_test)
"""
On va utiliser une architecture en couches (modèle Sequential), avec des couches denses :
"""
from keras.models import Sequential
from keras.layers import Dense
"""
On définit un modèle à deux couches cachées de 200 et 60 neurones
La dernière couche comporte X neurones (le nombre de classes) pour la classification :
"""
model = Sequential()
model.add(Dense(200, activation='relu'))
model.add(Dense(60, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))
"""
L'activation de la dernière couche est un softmax : la somme des valeurs de l'activation des neurones de la dernière couche est 1
(on interprète la sortie des derniers neurones comme une probabilité d'appartenance à la classe correspondante)
"""
"""
On "compile" le modèle, avec une categorical_crossentropy comme mesure de distance (distance probabiliste multi classes)
"""
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
train = model.fit(X_train , y_train , validation_data=(X_test,y_test), epochs=30, verbose=1)
"""
Pertinence :
"""
model.evaluate(X_test,y_test)
"""
La variable train mémorise l'historique des scores sur l'ensemble d'apprentissage :
"""
print(train.history['accuracy'])
"""
et sur l'ensemble de validation :
"""
print(train.history['val_accuracy'])
"""
On définit une fonction pour afficher un graphique des scores :
"""
def plot_scores(train) :
    accuracy = train.history['accuracy']
    val_accuracy = train.history['val_accuracy']
    epochs = range(len(accuracy))
    plt.plot(epochs, accuracy, 'b', label='Score apprentissage')
    plt.plot(epochs, val_accuracy, 'r', label='Score validation')
    plt.title('Scores')
    plt.legend()
    plt.show()
plot_scores(train)