#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Nov 29 23:59:14 2022

@author: leprince
"""

import matplotlib.pyplot as plt
import numpy as np


## RÉCUPÉRATION  DU JEU   DU JEU DE DONNÉES D'APPRENTISSAGE
fichier = open('donnees_app_KNN.txt','r')
liste_lignes = fichier.readlines()
fichier.close()

# pour contrôler : 
print(liste_lignes[0])
#pour voir l'effet de la méthode split:
print(liste_lignes[0].split(','))

donnees_apprentissage = []
for ligne in liste_lignes:
    ligne = ligne.strip() #pour enlever le '\n' final
    x , y , couleur  = ligne.split(',')   
    #Rem : ce sont toujours des chaînes de caractères
    donnees_apprentissage.append( ((float(x),float(y)), couleur ))

# pour contrôler : 
print(donnees_apprentissage[0])

#pour visualiser :
X_red = [d[0][0] for d in donnees_apprentissage if d[1]== 'red']
Y_red = [d[0][1] for d in donnees_apprentissage if d[1]== 'red']
plt.scatter(X_red,Y_red, color = 'red', marker = 's')


X_blue = [d[0][0] for d in donnees_apprentissage if d[1]== 'blue']
Y_blue = [d[0][1] for d in donnees_apprentissage if d[1]== 'blue']
plt.scatter(X_blue,Y_blue, color = 'blue', marker = 'd')

X_green = [d[0][0] for d in donnees_apprentissage if d[1]== 'green']
Y_green = [d[0][1] for d in donnees_apprentissage if d[1]== 'green']
plt.scatter(X_green,Y_green, color = 'green')

plt.show()

          
## MISE EN PLACE DE LA MÉTHODE

#exemple pour expliquer le tri suivant un critère :

def somme(C):
    return C[0]+C[1]
  
l = [ (0,1) , (4,5) , (1,3) , (2,1)]
ls = sorted(l , key = somme)
print(ls)



def dist(P1,P2):
    """renvoie la distance entre deux points,
    représentés sous forme d'une liste ou d'un couple de deux éléments"""
    
    return np.sqrt((P1[0]-P2[0])**2+(P1[1]-P2[1])**2)

def kNN(P,donnees,k):
    """renvoie les k plus proches voisins du point P dans la liste de points donnees ;
    la liste donnees est une liste de couples dont :
            - le premier terme est un couple représentant les coordonnées d'un point,
            - le deuxième terme est la catégorie de ce point
    """
    #on définit tout d'abord une fonction sur les couples de donnees 
    # qui va servir de critère de tri
    def distance_a_P(d):
        """ d est de la forme ((X,Y),'couleur')
        """
        return dist(P , d[0] ) 
    #On trie les données selon cette fonction de comparaison
    
    donneesTriees = sorted(donnees, key = distance_a_P)
    return donneesTriees[:k]

#test
P0 = (-0.1,1.9)
print(kNN(P0,donnees_apprentissage,5))


# Rappels sur les méthodes de parcours d'un dictionnaire   

d = {'red' : 0 , 'blue' : 0 , 'green' : 0}
d['yellow'] = 5

for a in d:
    print(a)
    
for b in d.items():
    print(b)
    
for cle , valeur in d.items():
    print(cle)
    print(valeur)
    
for valeur in d.values():
    print(valeur)
    
for clef in d.keys():
    print(clef)




def argMax(dico):
    """renvoie la liste des clefs dont les valeurs associées sont maximales"""
    M = - np.inf
    for valeur in dico.values():
        if valeur > M:
            M = valeur 
    l = []
    for a in dico.keys():
        if dico[a] == M:
            l.append(a)
    return l

#Tests :
dico1 = {'red' : 0 , 'blue' : 1 , 'green' : 0}
dico2 = {'red' : 0 , 'blue' : 1 , 'green' : 1}
print(argMax(dico1))
print(argMax(dico2))
    

def typekNN(P,donnees,k):
    """renvoie le type (parmi les trois couleurs) du point P
    détecté selon la méthode des k plus proche voisins,
    appliquée avec comme jeu de données la liste donnees.
    En cas d'égalité, la fonction renvoie une liste de plusieurs éléments"""
    kProchesVoisins = kNN(P,donnees,k)
    nombreCouleur = {'red' : 0 , 'blue' : 0 , 'green' : 0} 
              # ce dictionnaire  devra contenir le nombre de fois
              # où la couleur 'couleur' appraît dans la liste 
              # des k plus proches voisins de P
    for voisin in kProchesVoisins:
        nombreCouleur[voisin[1]] += 1
    couleurMax = argMax(nombreCouleur)
    return couleurMax
    
    
        
#test   
liste_points = [(0,0) , (-3,3) , (2,2) , (-0.5,2.5)]
for P in liste_points:
    print(typekNN(P,donnees_apprentissage,5))

    
# RÉCUPÉRATION  DU JEU DE DONNÉES TEST

fichier = open('donnees_test_KNN.txt','r')
liste_lignes = fichier.readlines()
fichier.close()

donnees_test = []
for ligne in liste_lignes:
    ligne = ligne.strip() #pour enlever le '\n' final
    x , y , couleur  = ligne.split(',')   
    donnees_test.append( ((float(x),float(y)), couleur ))

##OBTENTION DE LA MATRICE DE CONFUSION   
           
#dictionnaire faisant correspondre un numéro à chaque couleur
dC = {'red' : 0 , 'blue' : 1 , 'green' : 2} 

# On choisit une valeur de k :
k = 5

#initialisation de la matrice de confusion :
matConf = np.zeros((3,3))
#remplissage de la matrice de confusion
for d in donnees_test:
    l = typekNN(d[0],donnees_apprentissage,k)
    if len(l) == 1:
        matConf[ dC[d[1]] , dC[l[0]] ] += 1
    
    
        
print(matConf)



    
                 
