Connexion élèves

Choisir le(s) module(s) à installer :

Algorithme des k plus proches voisins

Nous allons voir dans cette partie une classe d'algorithmes permettant de classer des objets (au sens large) dans différentes catégories.
La décision prise par cet algorithme évolue au cours du temps, en fonction des choix qu'il a déjà effectué. C'est pourquoi il est classé dans un des algorithme les plus simples mettant en œuvre l'intelligence artificielle.

L'exemple historique des Iris

En 1936, le biologiste Edgar Anderson cherche à étudier la classification des Iris. Il s'intéresse plus particulièrement à 3 espèces :
Iris setosa
Iris versicolor
Iris virginica
Comme on peut le constater sur les photos, il n'est sûrement pas évident pour un non initié de déterminer l'espèce d'un Iris croisé dans la nature au hasard d'une promenade.

Les données

Edgar Anderson décide donc de mettre au point un test systématique permettant de différencier ces trois espèces.
Pour cela il réalise des mesures sur les pétales et les sépales des Iris : Il mesure :
  • La largeur et la longueur des sépales
  • La largeur et la longueur des pétales
pétale et sépale
Pour un ensemble d'Iris à la même saison, connaissant l'espèce de chaque fleur.
Pour simplifier le traitement des données nous ne prendrons en compte que les mesures des pétales.
Vous trouverez un extrait de ces données ici. Dans ce fichier les deux premières colonnes correspondent à la largeur et la longueur du pétale, la troisième colonne contient 0, 1 ou 2 en suivant le code suivant :
  1. Récupérez le fichier de donnée présenté ci-dessus.
  2. Visualisez ces données grâce à ce script :
    
    import matplotlib.pyplot as plt
    import csv
    
    iris=[]
    x0,x1,x2=[],[],[]
    y0,y1,y2=[],[],[]
    esp=[]
    
    with open("iris.csv",'r',encoding='utf-8') as f:
        lecteur=csv.reader(f,delimiter=',')
        for row in lecteur:
            iris.append(row)
    
        for i in range (1,len(iris)):
            if iris[i][2]=='0':
                x0.append(float(iris[i][0]))
                y0.append(float(iris[i][1]))
            if iris[i][2]=='1':
                x1.append(float(iris[i][0]))
                y1.append(float(iris[i][1]))
            if iris[i][2]=='2':
                x2.append(float(iris[i][0]))
                y2.append(float(iris[i][1]))
    
    plt.axis('equal')
    plt.scatter(x0, y0, color='r', label='iris setosa')
    plt.scatter(x1, y1, color='g', label='iris versicolor')
    plt.scatter(x2, y2, color='b', label='iris virginica')
    plt.legend()
    axes = plt.gca()
    axes.set_xlabel('longueur des pétales')
    axes.set_ylabel('largeur des pétales')
    axes.legend()
    plt.show()
    								

SOLUTION

Le problème

Le problème est de déterminer l'espèce d'un Iris inconnu, ne connaissant que la largeur et la longueur de ses pétales.

L'algorithme

Pour résoudre ce problème nous allons utiliser l'algorithme des k plus proches voisins.
Pour cela nous allons
  • Placer l'iris inconnu sur le plan
  • Chercher ses k plus proches voisins dans ce plan
  • Chercher l'espèce majoritaire parmi ces k voisins
  • Ajouter l'iris inconnu à l'espèce déterminée
Cet algorithme met en œuvre l'apprentissage automatique ou "machine learning". En effet Chaque nouvel élément va être associé à une espèce et donc enrichir les connaissances de l'ordinateur, qui pourra ainsi affiner ses choix par la suite.
On commence à voir apparaître une forme d'intelligence artificielle
Pour bien comprendre illustrons l'algorithme que l'on vient de décrire.
Voici trois iris inconnus ajoutés dans le plan sous la forme d'un point noir.
Iris inconnu 1
Iris inconnu 2
Iris inconnu 3
Pour les inconnus 1 et 2, nous pouvons déterminer "à l’œil" l'espèce de l'iris. Pour l'inconnu 3 cela va être plus compliqué, il va falloir calculer les distances aux iris voisins pour choisir l'espèce de l'inconnu 3.

Mise en œuvre de l'algorithme

Vous n'allez pas coder cet algorithme complètement, voici donc la structure du code que nous vous proposons et les structures de données associées :

Structures de données

Deux structures de données seront mises en oeuvre dans ce code.

Structure du code

Le code est structuré en fonctions indépendantes :

Travail à réaliser

Vous pouvez télécharger le programme kppv_iris_eleve.py ou le visualiser ci-dessous. Répondez aux questions sous le code.

import matplotlib.pyplot as plt
import csv
from math import sqrt

def affichage_iris(tab:list):
    '''
    ne rien toucher à cette fonction
    '''
    x0,x1,x2=[],[],[]
    y0,y1,y2=[],[],[]
    esp=[]

    for i in range (1,len(tab)):
        if tab[i][2]==0:
            x0.append(tab[i][0])
            y0.append(tab[i][1])
        if tab[i][2]==1:
            x1.append(tab[i][0])
            y1.append(tab[i][1])
        if tab[i][2]==2:
             x2.append(tab[i][0])
             y2.append(tab[i][1])
    plt.axis('equal')
    plt.scatter(x0, y0, color='r', label='iris setosa')
    plt.scatter(x1, y1, color='g', label='iris versicolor')
    plt.scatter(x2, y2, color='b', label='iris virginica')
    plt.legend()
    axes = plt.gca()
    axes.set_xlabel('longueur des pétales')
    axes.set_ylabel('largeur des pétales')
    axes.legend()
    plt.show()


def recup_donnees(nomDeFichier)->list:
    '''
    à partir du nom de fichier, cette fonction récupère les données et les renvoie sous forme de tableau de tableaux
    ne rien toucher à cette fonction
    '''
    iris=[]
    with open(nomDeFichier,'r',encoding='utf-8') as f:
        lecteur=csv.reader(f,delimiter=',')
        for row in lecteur:
            iris.append(row)
        for i in range (1,len(iris)):
            for j in range(2):
                iris[i][j]=float(iris[i][j])
            iris[i][2]=int(iris[i][j])
        return iris

def mini_iris(tab:list):
    '''
    recherche le minimu et enlève l'élément du tableau de tableaux
    renvoie le minimum et le tableau de tableaux modifié
    '''
    min=100000
    indicemin=0
    for i in range (len(tab))
        if tab[i][3] < min:
            min=tab[i][3]
            indicemin=i
    min=tab.pop(indicemin)
    return min,tab

def distance(x1:float,y1:float,x2:float,y2:float)->float
    '''
    calcule la "distance" entre deux iris
    '''
    return sqrt((x2-x1)**2+(y2-y1)**2)

def kppv_iris(iris:list, larg:float,haut:float,nbvoisins:int)-> list:
    '''
    recherche des nbvoisins les plus proches pour déterminer l'espèce de l'iris donc les pétales mesurent larg x haut.
    Une fois l'espèce déterminée, le nouvel iris est ajouté au tableau iris qui est renvoyé modifié en fin de fonction.
    '''
    #copie du tableau de tableaux iris dans le tableau de tableaux iris_kppv
    iris_kppv=[[iris[i][j] for j in range(3)]for i in range(1,len(iris))]

    #calcul des distances à toutes les autres fleurs et stockage dans le tableau de tableaux iris_kppv
    for i in range (0,len(iris_kppv)):
        iris_kppv[i].append(distance(larg,haut,iris_kppv[i][0],iris_kppv[i][1]))

    #recherche des k voisins les plus proches
    voisins=[]
    for i in range (nbvoisins):
        voisin_proche,iris_kppv=mini_iris(iris_kppv)
        voisins.append(voisin_proche)

    #recherche de l'espèce majoritaire des k voisins
    #le tableau espece va contenir l'effectif de chaque espèce : espece[0]->setosa ; espece[1]->versicolor ; espece[2]->virginica
    espece=[0,0,0]
    #on parcourt le tableau de tableaux contenant les proches voisins
    for i in range (len(voisins)):
        if voisins[i][2]==0:
            pass # ... supprimer le pass puis compléter la ligne
        if voisins[i][2]==1:
            pass # ... supprimer le pass puis compléter la ligne
        if voisins[i][2]==2:
            pass # ... supprimer le pass puis compléter la ligne

    #ajout de l'iris inconnu au tableaua de taableaux "iris"
    iris.append([larg,haut,espece.index(max(espece))])

    return iris
#####################################################

#récupération des données
fleurs=recup_donnees('iris.csv')

#application de l'algorithme des k plus proches voisins

#affichage des données
affichage_iris(fleurs)
					
Le code ci-dessus contient des erreurs et est incomplet.
  1. Téléchargez le code et exécutez le (en le plaçant dans le même répertoire que le fichier iris.csv. Une erreur de syntaxe apparaît, corrigez là
  2. Une fois le première erreur corrigée, une deuxième erreur de syntaxe apparaît, corrigez là (attention c'est un peu plus subtil ici))
  3. Une fois les deux erreurs de syntaxe corrigées, le programme doit s'exécuter normalement et afficher le graphique des données des iris.
    Complétez le programme principal pour ajouter au tableau de tableaux fleursl'iris inconnu dont le pétale mesure 5.5 cm de longueur et 1.95 cm de largeur. On s'appuiera pour cela sur ses 5 plus proches voisins.
  4. Le point correspondant à l'iris est ajouté dans le plan mais vous pouvez constater qu'ils n'est pas classé dans la bonne espèce.
    C'est logique, il manque trois lignes au programme (lignes 96, 98 et 100).
    Complétez ces trois lignes et testez à nouveau le programme, si vous avez bien compris, cela doit fonctionner.

SOLUTION

Machine learning