<jupyter_start><jupyter_text>Exercice 2 - Le problème des iris K plus proches voisins - Application directe du cours Partie A : présentation du problèmeAfin de travailler sur un exemple, nous allons utiliser un jeu de données relativement connu dans le monde du machine learning : le jeu de données "iris".En 1936, <NAME> a collecté des données sur 3 espèces d'iris : "iris setosa", "iris virginica" et "iris versicolor" iris_setosa.jpeg ![](iris_setosa.jpeg)iris_virginica.jpeg ![](iris_virginica.jpeg)iris_versicolorjpeg ![](iris_versicolor.jpeg) Travail :1. Ouvrir avec un éditeur de texte et analyser le fichier iris.csv.Noter le nom des descripteurs. * petal_length* petal_width* species 2. Quel est le nombre d'enregistrements * 150  Partie B : lecture des données1. Compléter le code ci-dessous pour lire le fichier iris.csv et afficher les données.<jupyter_code>import csv
from pprint import pprint

def lire_csv(fichier):
    with open(fichier, newline='') as fichier_csv:
        #reader = csv.DictReader(fichierCSV, delimiter=',', encoding='utf-8', quoting=csv.QUOTE_NONE)
        reader = csv.DictReader(fichier_csv, delimiter=',')
        
        return [dict(ligne) for ligne in reader]


fichier = "iris.csv"
liste_iris = lire_csv(fichier)

pprint(liste_iris[:4])
pprint(liste_iris[-5:-1])<jupyter_output>[{'petal_length': '5.2', 'petal_width': '2.3', 'species': '2'},
 {'petal_length': '5.0', 'petal_width': '1.9', 'species': '2'},
 {'petal_length': '5.2', 'petal_width': '2.0', 'species': '2'},
 {'petal_length': '5.4', 'petal_width': '2.3', 'species': '2'}]<jupyter_text>2. Compléter la fonction ci-dessous pour qu'elle retourne une liste de nombres de type float qui correspondent à une colonne d'un tableau.<jupyter_code>def dico_vers_float(liste_dicos, descripteur):
    liste = [float(dico[descripteur]) for dico in liste_dicos]
    
    return liste<jupyter_output><empty_output><jupyter_text>3. Tester la fonction pour construire les listes des longueurs et des largeurs.<jupyter_code>liste_longueur = dico_vers_float(liste_iris, 'petal_length')
liste_largeur  = dico_vers_float(liste_iris, 'petal_width')<jupyter_output><empty_output><jupyter_text>Afficher les longueurs<jupyter_code>print(liste_longueur)<jupyter_output>[1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5, 1.5, 1.6, 1.4, 1.1, 1.2, 1.5, 1.3, 1.4, 1.7, 1.5, 1.7, 1.5, 1.0, 1.7, 1.9, 1.6, 1.6, 1.5, 1.4, 1.6, 1.6, 1.5, 1.5, 1.4, 1.5, 1.2, 1.3, 1.5, 1.3, 1.5, 1.3, 1.3, 1.3, 1.6, 1.9, 1.4, 1.6, 1.4, 1.5, 1.4, 4.7, 4.5, 4.9, 4.0, 4.6, 4.5, 4.7, 3.3, 4.6, 3.9, 3.5, 4.2, 4.0, 4.7, 3.6, 4.4, 4.5, 4.1, 4.5, 3.9, 4.8, 4.0, 4.9, 4.7, 4.3, 4.4, 4.8, 5.0, 4.5, 3.5, 3.8, 3.7, 3.9, 5.1, 4.5, 4.5, 4.7, 4.4, 4.1, 4.0, 4.4, 4.6, 4.0, 3.3, 4.2, 4.2, 4.2, 4.3, 3.0, 4.1, 6.0, 5.1, 5.9, 5.6, 5.8, 6.6, 4.5, 6.3, 5.8, 6.1, 5.1, 5.3, 5.5, 5.0, 5.1, 5.3, 5.5, 6.7, 6.9, 5.0, 5.7, 4.9, 6.7, 4.9, 5.7, 6.0, 4.8, 4.9, 5.6, 5.8, 6.1, 6.4, 5.6, 5.1, 5.6, 6.1, 5.6, 5.5, 4.8, 5.4, 5.6, 5.1, 5.1, 5.9, 5.7, 5.2, 5.0, 5.2, 5.4, 5.1]<jupyter_text>Afficher les largeurs<jupyter_code>print(liste_largeur)<jupyter_output>[0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.2, 0.1, 0.1, 0.2, 0.4, 0.4, 0.3, 0.3, 0.3, 0.2, 0.4, 0.2, 0.5, 0.2, 0.2, 0.4, 0.2, 0.2, 0.2, 0.2, 0.4, 0.1, 0.2, 0.1, 0.2, 0.2, 0.1, 0.2, 0.2, 0.3, 0.3, 0.2, 0.6, 0.4, 0.3, 0.2, 0.2, 0.2, 0.2, 1.4, 1.5, 1.5, 1.3, 1.5, 1.3, 1.6, 1.0, 1.3, 1.4, 1.0, 1.5, 1.0, 1.4, 1.3, 1.4, 1.5, 1.0, 1.5, 1.1, 1.8, 1.3, 1.5, 1.2, 1.3, 1.4, 1.4, 1.7, 1.5, 1.0, 1.1, 1.0, 1.2, 1.6, 1.5, 1.6, 1.5, 1.3, 1.3, 1.3, 1.2, 1.4, 1.2, 1.0, 1.3, 1.2, 1.3, 1.3, 1.1, 1.3, 2.5, 1.9, 2.1, 1.8, 2.2, 2.1, 1.7, 1.8, 1.8, 2.5, 2.0, 1.9, 2.1, 2.0, 2.4, 2.3, 1.8, 2.2, 2.3, 1.5, 2.3, 2.0, 2.0, 1.8, 2.1, 1.8, 1.8, 1.8, 2.1, 1.6, 1.9, 2.0, 2.2, 1.5, 1.4, 2.3, 2.4, 1.8, 1.8, 2.1, 2.4, 2.3, 1.9, 2.3, 2.5, 2.3, 1.9, 2.0, 2.3, 1.8]<jupyter_text>4. Compléter la fonction ci-dessous pour qu'elle retourne une liste de nombres  de type int qui correspondent à une colonne d'un tableau.<jupyter_code>def dico_vers_int(liste_dicos, descripteur):
    liste = [int(dico[descripteur]) for dico in liste_dicos]
    return liste<jupyter_output><empty_output><jupyter_text>5. Tester la fonction pour construire la liste des espèces.<jupyter_code>liste_espece = dico_vers_int(liste_iris, 'species')
print(liste_espece)<jupyter_output>[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]<jupyter_text>Partie C : prédiction1. Écrire une fonction qui calcule la distance Euclidienne entre deux points.<jupyter_code>def distanceE1(xA, yA, xB, yB):
    return sqrt((xB - xA) ** 2 + (yB - yA) ** 2)
from math import sqrt

print(distanceE1(0, 2, 3, 5)) # A(0, 2) et B(3, 5)<jupyter_output>4.242640687119285<jupyter_text>2. Écrire une fonctions distances qui calcule les distances entre mystere et les éléments des listes listeLongueur et listeLargeur.<jupyter_code>def distances(listeX, listeY, mystere):
    #mystere[0] : abscisse
    #mystere[1] : ordonnées
    #Retourne la liste des distances entre mystere et les autres éléments

    liste_distances = []
    
    for i in range(len(listeX)):
        d = distanceE1(listeX[i], listeY[i], mystere[0], mystere[1])
        liste_distances.append(d)
    return liste_distances
longueur = 2.5
largeur  = 0.75
mystere  = (longueur, largeur)

print(distances(liste_longueur, liste_largeur, mystere))<jupyter_output>[1.2298373876248845, 1.2298373876248845, 1.3200378782444084, 1.1412712210513327, 1.2298373876248845, 0.873212459828649, 1.1884864324004714, 1.1412712210513327, 1.2298373876248845, 1.1926860441876563, 1.1412712210513327, 1.0547511554864493, 1.2776932339180638, 1.543534904043313, 1.4115594213493106, 1.0594810050208545, 1.25, 1.1884864324004714, 0.9178779875342911, 1.0965856099730655, 0.97082439194738, 1.0594810050208545, 1.5976545308670458, 0.8381527307120106, 0.8139410298049854, 1.0547511554864493, 0.9656603957913982, 1.1412712210513327, 1.2298373876248845, 1.0547511554864493, 1.0547511554864493, 1.0594810050208545, 1.1926860441876563, 1.2298373876248845, 1.1926860441876563, 1.4115594213493106, 1.3200378782444084, 1.1926860441876563, 1.3200378782444084, 1.1412712210513327, 1.2816005617976296, 1.2816005617976296, 1.3200378782444084, 0.9124143795447328, 0.6946221994724903, 1.1884864324004714, 1.0547511554864493, 1.2298373876248845, 1.1412712210513327, 1.2298373876248845, 2.294013949390892[...]<jupyter_text>3. Écrire une fonction qui détermine les k plus proches voisins.<jupyter_code>def choix_premier(element):
    return element[0]


def k_plus_proches_voisins(listeX, listeY, liste_famille, mystere, k):
    # Calculer les distances
    liste_distances = distances(liste_longueur, liste_largeur, mystere)
    
    # Associer distance et famille
    liste_distances_familles = list(zip(liste_distances, liste_famille)) # Transformer deux listes en une liste de couples
     
     
    # Trier la liste en fonction de la distance
    distance_triee = sorted(liste_distances_familles, key=choix_premier)
    
    # Choisir les k premiers
    k_premiers = distance_triee[:k]
      
    return k_premiers
pprint(k_plus_proches_voisins(liste_longueur, liste_largeur, liste_espece, mystere, 5))<jupyter_output>[(0.6103277807866851, 1),
 (0.6946221994724903, 0),
 (0.8139410298049854, 0),
 (0.8381527307120104, 1),
 (0.8381527307120104, 1)]<jupyter_text>4. Écrire une fonction qui retourne la prédiction de la famille à laquelle appartient l'iris mystère.<jupyter_code>def prediction(liste_longueur, liste_largeur, liste_espece, mystere, k):
    # Détermine la famille de l'objet mystère
    k_premiers = k_plus_proches_voisins(liste_longueur, liste_largeur, liste_espece, mystere, k)
    
    # Calculer les effectifs de chaque famille
    liste_familles = [0, 1, 2]
    #                 0  1  2
    
    # Initialiser les effectifs à 0 
    effectif_familles = [0, 0, 0]
    #                    0  1  2
    
    for (distance, famille)  in  k_premiers:
        i = liste_familles.index(famille)       # Recherche l'index de famille actuelle
        effectif_familles[i] += 1               # Incrémenter l'effectif de la famille actuelle
    
    # Déterminer la famille avec l'effectif le plus élevé
    effectif_max = max(effectif_familles)
    
    i =  effectif_familles.index(effectif_max)
    
    return liste_familles[i]   # Famille avec l'effectif le plus élevé
k = 5
print(prediction(liste_longueur, liste_largeur, liste_espece, mystere, k))<jupyter_output>1<jupyter_text>5. Tester les fonctions.<jupyter_code>fichier        = 'iris.csv'
liste_iris     = lire_csv(fichier)
liste_longueur = dico_vers_float(liste_iris, 'petal_length')
liste_largeur  = dico_vers_float(liste_iris, 'petal_width')
liste_espece   = dico_vers_int(liste_iris, 'species')


# Afficher les listes à partir du fchier iris.csv
#print(listeLongueur)
#print(listeLargeur)
#print(listeEspece)

# Iris mystère
longueur = 2.5
largeur  = 0.75
mystere  = (longueur, largeur)


# Paramétrage de l'algorithme des k plus proches voisins              
k = 1 # On peut tester avec 1, 3, 5 ou 10

prediction_num = prediction(liste_longueur, liste_largeur, liste_espece, mystere, k)
print(prediction_num)<jupyter_output>1<jupyter_text>6. Écrire une fonction pour déterminer le nom de la famille à partir de son numéro.<jupyter_code>def predir_famille(prediction_num, noms_familles):
    return noms_familles[str(prediction_num)]

# Association notation fichier et noms des iris
noms_familles = {
    '0' : 'iris setosa',
    '1' : 'iris versicolor', 
    '2' : 'iris virginica'
}
print(prediction_num, predir_famille(prediction_num, noms_familles))<jupyter_output>1 iris versicolor<jupyter_text>Partie D : afficher un graphique<jupyter_code>setosa_longueur     = [liste_longueur[i] for i in range(len(liste_espece)) if liste_espece[i] == 0]
setosa_largeur      = [liste_largeur[i] for i in range(len(liste_espece)) if liste_espece[i] == 0]
versicolor_longueur = [liste_longueur[i] for i in range(len(liste_espece)) if liste_espece[i] == 1]
versicolor_largeur  = [liste_largeur[i] for i in range(len(liste_espece)) if liste_espece[i] == 1]
virginica_longueur  = [liste_longueur[i] for i in range(len(liste_espece)) if liste_espece[i] == 2]
virginica_largeur   = [liste_largeur[i] for i in range(len(liste_espece)) if liste_espece[i] == 2]
print(versicolor_longueur)
print(versicolor_largeur)
import matplotlib.pyplot as plt

plt.figure()

plt.scatter(setosa_longueur, setosa_largeur, color='g', label='Setosa')
plt.scatter(versicolor_longueur, versicolor_largeur, color='r', label='Versicolor')
plt.scatter(virginica_longueur, virginica_largeur, color='b', label='Virginica')
plt.scatter(mystere[0], mystere[1], color='k', label='<NAME>')

plt.xlabel("Longueur")
plt.ylabel("Largeur")

plt.legend()
plt.grid()

plt.show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.15340553119126465, 'fraction_numerical': 0.16235567886870134, 'mean_word_length': 4.130394857667585, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 32, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '14', 'dir': 'jupyter-structured-clean-dedup', 'id': '119697', 'license': 'MIT', 'n_tokens_mistral': 6328, 'n_tokens_neox': 5235, 'n_words': 1218, 'path': '11_k_plus_proches/exercices/ex2/ex2.ipynb', 'repo_name': 'icecodder/nsi', 'size': '11187'}