#!/usr/bin/env python3 # -*- coding: utf-8 -* """ Vous allez definir une classe pour chaque algorithme que vous allez développer, votre classe doit contenit au moins les 3 methodes definies ici bas, * train : pour entrainer le modèle sur l'ensemble d'entrainement * predict : pour prédire la classe d'un exemple donné * test : pour tester sur l'ensemble de test vous pouvez rajouter d'autres méthodes qui peuvent vous etre utiles, mais moi je vais avoir besoin de tester les méthodes test, predict et test de votre code. """ import numpy as np def minkowski_distance(x,y,p_value): return pow(sum(pow(abs(a-b),p_value) for a,b in zip(x, y)),1/p_value) def mode(a): u, c = np.unique(a, return_counts=True) return u[c.argmax()] # le nom de votre classe # BayesNaif pour le modèle bayesien naif # Knn pour le modèle des k plus proches voisins class Knn: #nom de la class à changer def __init__(self, k=5, **kwargs): """ c'est un Initializer. Vous pouvez passer d'autre paramètres au besoin, c'est à vous d'utiliser vos propres notations """ self.k=k def set_best_k(self, train, train_labels, nb_split, k_potentiel): ## Création des échantillons de validation croisée shuffle_indices = np.random.permutation([i for i in range(train.shape[0])]) validation_index = np.array_split(shuffle_indices, nb_split) train_index = [] for i in range(nb_split): train_index.append(list(set(shuffle_indices)-set(validation_index[i]))) ## Itération sur les valeurs de K et sur les échantillons de validation croisée accuracy_cv = np.empty((len(k_potentiel),nb_split)) for k_index in range(len(k_potentiel)): for i in range(nb_split): self.k=k_potentiel[k_index] self.train(train[train_index[i]], train_labels[train_index[i]], verbose=False) cm,accuracy,precision,recall = self.test(train[validation_index[i]], train_labels[validation_index[i]], verbose=False) accuracy_cv[k_index][i] = accuracy ## Calcul de la moyenne mean_accuracy = accuracy_cv.mean(axis=1) ## Extraction du meilleur K best_k = k_potentiel[int(min(np.argwhere(mean_accuracy==max(mean_accuracy))))] ## Assignation self.k=best_k ## Retourner la valeur return best_k def train(self, train, train_labels, verbose=True): #vous pouvez rajouter d'autres attribus au besoin """ c'est la méthode qui va entrainer votre modèle, train est une matrice de type Numpy et de taille nxm, avec n : le nombre d'exemple d'entrainement dans le dataset m : le mobre d'attribus (le nombre de caractéristiques) train_labels : est une matrice numpy de taille nx1 vous pouvez rajouter d'autres arguments, il suffit juste de les expliquer en commentaire ------------ Après avoir fait l'entrainement, faites maintenant le test sur les données d'entrainement IMPORTANT : Vous devez afficher ici avec la commande print() de python, - la matrice de confision (confusion matrix) - l'accuracy - la précision (precision) - le rappel (recall) Bien entendu ces tests doivent etre faits sur les données d'entrainement nous allons faire d'autres tests sur les données de test dans la méthode test() """ # on fait seulement utiliser les données du jeu d'entrainement comme paramètre d'un modèle Knn self.train_set=train self.train_labels=train_labels n,m = train.shape nn=np.empty((n,self.k,2)) self.minkowski_p=m # On trouve les k plus proches voisins et leur distance pour chacunes des observations du training set # On enlève la valeur testée de la liste des points pour lesquels on mesure la distance car on sait qu'elle vaut 0. # On veut tester sur les autres points seulement for x in range(n): i_range = [i for i in range(n)] i_range.pop(x) nn[x,:,0]=i_range[0:self.k] nn[x,:,1]=np.apply_along_axis(minkowski_distance,1,self.train_set[i_range[0:self.k]],train[x],self.minkowski_p) for i in i_range[self.k:n]: dist = minkowski_distance(self.train_set[i],train[x],self.minkowski_p) nn_dist=nn[x,:,1] distdiff = nn_dist-dist max_distdiff=max(distdiff) if(max_distdiff>0): pos_changement = np.argwhere(nn_dist==max(nn_dist))[0] nn[x,pos_changement,0]=i nn[x,pos_changement,1]=max_distdiff # on retrouve le label modal pour chacunes des observations nn_labels = self.train_labels[nn[:,:,0].astype(np.int)] nn_mode_label = np.apply_along_axis(mode,1,nn_labels) # on construit la matrice de confusion cm = self.confusion_matrix(train_labels,nn_mode_label) accuracy, precision, recall = self.prediction_metrics(cm,train_labels,nn_mode_label) if (verbose): self.print_prediction_metrics(cm,accuracy,precision,recall) return cm,accuracy,precision,recall def predict(self, exemple, label, verbose=True): """ Prédire la classe d'un exemple donné en entrée exemple est de taille 1xm si la valeur retournée est la meme que la veleur dans label alors l'exemple est bien classifié, si non c'est une missclassification """ n,m = self.train_set.shape nn=np.empty((self.k,2)) nn[:,0]=[i for i in range(self.k)] nn[:,1]=np.apply_along_axis(minkowski_distance,1,self.train_set[0:self.k],exemple,self.minkowski_p) for i in range(self.k,n): dist = minkowski_distance(self.train_set[i],exemple,self.minkowski_p) nn_dist=nn[:,1] distdiff = nn_dist-dist max_distdiff=max(distdiff) if(max_distdiff>0): pos_changement = np.argwhere(nn_dist==max(nn_dist))[0] nn[pos_changement,0]=i nn[pos_changement,1]=max_distdiff nn_labels = self.train_labels[nn[:,0].astype(np.int)] nn_mode_label = mode(nn_labels) if (verbose): print("Observé:"+str(label)+" Prédit:"+str(nn_mode_label)) return (nn_mode_label,label) def test(self, test, test_labels, verbose=True): """ c'est la méthode qui va tester votre modèle sur les données de test l'argument test est une matrice de type Numpy et de taille nxm, avec n : le nombre d'exemple de test dans le dataset m : le mobre d'attribus (le nombre de caractéristiques) test_labels : est une matrice numpy de taille nx1 vous pouvez rajouter d'autres arguments, il suffit juste de les expliquer en commentaire Faites le test sur les données de test, et afficher : - la matrice de confision (confusion matrix) - l'accuracy - la précision (precision) - le rappel (recall) Bien entendu ces tests doivent etre faits sur les données de test seulement """ n,m = test.shape n_ex,m_ex = self.train_set.shape nn=np.empty((n,self.k,2)) # Boucle sur chaque ligne du jeu de test for x in range(n): nn[x,:,0]=[i for i in range(self.k)] nn[x,:,1]=np.apply_along_axis(minkowski_distance,1,self.train_set[0:self.k],test[x],self.minkowski_p) for i in range(self.k,n_ex): dist = minkowski_distance(self.train_set[i],test[x],self.minkowski_p) nn_dist=nn[x,:,1] distdiff = nn_dist-dist max_distdiff=max(distdiff) if(max_distdiff>0): pos_changement = np.argwhere(nn_dist==max(nn_dist))[0] nn[x,pos_changement,0]=i nn[x,pos_changement,1]=max_distdiff nn_labels = self.train_labels[nn[:,:,0].astype(np.int)] nn_mode_label = np.apply_along_axis(mode,1,nn_labels) # on construit la matrice de confusion cm = self.confusion_matrix(test_labels,nn_mode_label) accuracy, precision, recall = self.prediction_metrics(cm,test_labels,nn_mode_label) if (verbose): self.print_prediction_metrics(cm,accuracy,precision,recall) return cm,accuracy,precision,recall def confusion_matrix(self,obs_labels,pred_labels): """ Retourne la matrice de confusion Prend en entrée deux vecteurs d'étiquettes: observations et prédictions Retourne une matrice NumPy """ unique_obs_labels=np.unique(obs_labels) nb_unique_obs_labels=(unique_obs_labels.shape)[0] confusion_matrix = np.zeros((nb_unique_obs_labels,nb_unique_obs_labels)) for observed,predicted in zip(obs_labels,pred_labels): confusion_matrix[observed][predicted] += 1 return confusion_matrix def prediction_metrics(self,cm,obs_labels,pred_labels): """ Cette fonction retourne les métriques accuracy, precision et recall Elle prend en entrée la matrice de confusion et les vecteurs d'étiquettes: observations et prédictions accuracy=(tp+tn)/all precision=tp/(tp+fp) recall=tp/(tp+fn) """ accuracy = (obs_labels == pred_labels).sum() / float(len(obs_labels)) precision=[] recall=[] for label_num in np.unique(obs_labels): precision.append(cm[label_num,label_num] / sum(cm[:,label_num])) recall.append(cm[label_num,label_num] / sum(cm[label_num,:])) return accuracy, precision, recall def print_prediction_metrics(self,cm,accuracy,precision,recall): """ Cette fonction imprime la matrice de confusion et les métriques """ print("Matrice de confusion:") print(cm) print("\nAccuracy:") print(accuracy) print("\nPrecision:") print(precision) print("\nRecall") print(recall) # Vous pouvez rajouter d'autres méthodes et fonctions, # il suffit juste de les commenter.