##############################################################################
###                Algorithme des KNN (K plus proches voisins)             ###
##############################################################################

import matplotlib.pyplot as plt
import numpy as np
from sklearn import datasets

### Données d'apprentissage

Donnees_appr = [['t1',[1,28.0]], ['t1',[3,27.2]], ['t1',[10,37.6]], ['t1',[13,40.7]], ['t2',[2,30.1]], ['t2',[3,26.0]], ['t2',[10,39.1]], ['t2',[15,35.5]], ['t1',[0,30.1]], ['t1',[5,33.1]], ['t1',[8,32.1]], ['t1',[10,27.6]], ['t2',[12,36.0]], ['t2',[16,37.9]], ['t2',[12,34.1]], ['t2',[10,34.7]]]

### Données à catégoriser

Cibles = [[5,28.4],[12,38.9],[10,31.1]]

### Affichage des données d'apprentissage et des cibles à catégoriser

def affiche_donnees(tab,cib):
    liste_x_1=[]
    liste_y_1=[]
    liste_x_2=[]
    liste_y_2=[]
    for elem in tab:
        if elem[0]=='t1':
            liste_x_1.append(elem[1][0])
            liste_y_1.append(elem[1][1])
        if elem[0]=='t2':
            liste_x_2.append(elem[1][0])
            liste_y_2.append(elem[1][1])
    plt.axis('equal')
    plt.xlabel('Caractéristique 1')
    plt.ylabel('Caractérstique 2')
    plt.title('Représentation des Données catégorisées et Cibles')
    plt.grid()
    plt.scatter(liste_x_1,liste_y_1, label="type 't1'", marker ='*',color='g',s=80)
    plt.scatter(liste_x_2,liste_y_2, label="type 't2'",marker='o',color='b',s=40)
    plt.scatter(cib[0][0],cib[0][1], label='1iere cible = Cibles[0]',marker='s',color='r', s=80)
    plt.scatter(cib[1][0],cib[1][1], label='2ième cible = Cibles[1]',marker='v',color='r', s=80)
    plt.scatter(cib[2][0],cib[2][1], label='3ième cible = Cibles[2]',marker='^',color='r', s=80)
    plt.legend(loc= 'upper left')
    plt.show()

affiche_donnees(Donnees_appr,Cibles)

## Question 1 : Calcul de la distance

# def distance(p1:list,p2:list)->float:






## Question 2 : Liste des données catégorisées triées par la distance à la cible

# def liste_tries_cat_dist(Data_appr:list, cible:list) ->list:







## Question 3 : Catégorisation d'une cible

# def classification(Data_appr:list,cible:list,k:int):










## Question 4 : Influence du facteur k sur la prédiction

def predictions_fct_k(Data_appr:list,Liste_cibles:list):
    for k in range(1,10,2):
        print('k =',k,end='  =>  ')
        for num_cible in range(len(Liste_cibles)):
            type=classification(Data_appr,Liste_cibles[num_cible],k)
            print('Catégorie de la cible',num_cible+1,'=',type,end='   ')
        print('')

## Données de reconnaissance de caractères (chiffres uniquement)

def Creation_Donnees(d):
    tab=[]
    n=len(d['data'])
    for i in range(n):
        tab.append((d['target'][i],d['data'][i]))
    return tab

digits = datasets.load_digits()
Donnees=Creation_Donnees(digits)
jeu_a=Donnees[:1000]
jeu_t=Donnees[1000:1100]

def visualise(indice:int):
    plt.figure(1, figsize=(2, 2))
    plt.imshow(digits['images'][indice], cmap=plt.cm.gray_r, interpolation="nearest")
    plt.title(digits['target'][indice])
    plt.show()

## Question 5 : Matrice de confusion

def mat_de_conf(data:list,test:list,k:int)->np.array:
    Liste_categories=[]                     #
    for elem in test:                       # Lignes de code
        if elem[0] not in Liste_categories: # pour initialiser la
            Liste_categories.append(elem[0])# matrice de confusion
    n=len(Liste_categories)                 #
    M=np.zeros((n,n))                       #
                                                    #
                                                    # Lignes de code
                                                    # à completer
                                                    #
    for i in range(n):                      # Lignes de code pour passer
        somme=sum(M[i])                     # de la matrice (avec le nombre
        for j in range(n):                  # d'occurences) à la matrice
            M[i,j]=int(M[i,j]/somme*100)    # normalisée (en pourcentage)
    return M

## Question 6 :

# Il semble qu'on ait la matrice de confusion avec une trace maximale pour k = 15.
# 15 Plus Proches Voisins semble donc être un bon choix pour l'algorithme

## Question 7 :

# Avec ces données et k = 15 on obtient 100% de prédictions exactes.
# Cela ne signifie pas pour autant que l'algorithme donera une prédiction juste
#  dans 100% des cas. D'autre donnnées peuvent conduire à de fausses prédictions