Les k plus proches voisins (k-NN)
Introduction
Les cours précédents portaient sur des algorithmes déterministes (qui produisent toujours la même sortie pour une même entrée) : on sait exactement ce qu'ils calculent, et on peut prouver leur correction. Ce dernier cours change de registre — il introduit un algorithme d'apprentissage, le k plus proches voisins (ou k-Nearest Neighbors, k-NN). On lui fournit des exemples déjà étiquetés, et il classe un nouvel exemple par ressemblance aux exemples connus. C'est un avant-goût de l'apprentissage automatique que vous approfondirez en Terminale et au-delà.
Le cœur du concept
Problème : on vous donne un ensemble de points dans un plan, chacun étiqueté avec une classe (par exemple « chat » ou « chien », ou « iris setosa » / « iris versicolor »). On vous présente un nouveau point sans étiquette. Quelle classe lui attribuer ?
Idée du k-NN :
- Calculer la distance entre le nouveau point et chaque point étiqueté.
- Sélectionner les plus proches.
- Regarder leur classe majoritaire parmi ces voisins.
- Attribuer cette classe au nouveau point.
La distance euclidienne
Pour mesurer à quel point deux points sont proches, on utilise une distance. La plus classique est la distance euclidienne — celle de la règle, en ligne droite.
En 1D, c'est tout simplement l'écart entre deux nombres : pour deux points et sur une droite,
En 2D, on applique le théorème de Pythagore au triangle rectangle formé par les deux points. Pour deux points et :
En Python :
import math
def distance(a, b):
"""Distance euclidienne entre deux points 2D."""
return math.sqrt((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2)
print(distance((0, 0), (3, 4))) # 5.0
L'algorithme k-NN complet
zip(a, b)parcourt en parallèle deux listes (utile pour comparer composante par composante les coordonnées de deux points).Counter(voisins).most_common(1)compte rapidement les occurrences et renvoie la classe majoritaire.[expr for x in liste]est une list-comprehension : on construit une nouvelle liste en une ligne.
import math
from collections import Counter
def distance(a, b):
return math.sqrt(sum((ai - bi) ** 2 for ai, bi in zip(a, b)))
def knn(donnees, nouveau, k):
"""donnees : liste de tuples (point, classe).
nouveau : un point à classer.
k : nombre de voisins à considérer.
Retourne la classe prédite pour nouveau."""
# 1. Distances entre nouveau et chaque point étiqueté
distances = [(distance(point, nouveau), classe) for point, classe in donnees]
# 2. Tri par distance croissante
distances.sort()
# 3. Récupération des classes des k plus proches
voisins = [classe for _, classe in distances[:k]]
# 4. Vote majoritaire
return Counter(voisins).most_common(1)[0][0]
# Exemple : classifier un fruit par son poids et son diamètre
fruits = [
((150, 7), "pomme"),
((170, 7.5), "pomme"),
((140, 6.8), "pomme"),
((120, 5.5), "mandarine"),
((110, 5), "mandarine"),
((130, 5.8), "mandarine"),
]
inconnu = (135, 6.2)
print(knn(fruits, inconnu, k=3))
# 'mandarine' ou 'pomme' selon les plus proches
Choisir
Le choix de influence fortement le résultat.
- : on prend la classe du voisin le plus proche, point. Très sensible au bruit (un seul exemple aberrant peut faire basculer la classification).
- grand : on lisse, on moyenne, mais on perd la finesse locale. Si nombre total d'exemples, on retombe sur la classe globalement majoritaire quel que soit le nouveau point.
Pourquoi choisit-on souvent k impair ?
C'est un algorithme d'apprentissage
Le k-NN apprend à partir d'exemples étiquetés — il n'a pas besoin qu'on lui donne de règle explicite (« si poids > 140 alors pomme »). Il déduit ces règles implicitement de la disposition des points. C'est ce qu'on appelle l'apprentissage supervisé : on apprend à partir d'exemples dont on connaît la classe.
Trois grandes familles d'apprentissage automatique
- Supervisé : exemples étiquetés (classe connue). Le k-NN en est un cas.
- Non supervisé : exemples sans étiquette, on cherche des structures (groupes, regroupements).
- Par renforcement : on apprend en interagissant avec un environnement, par essais et erreurs.
Le k-NN est l'un des plus simples — pas de phase d'entraînement à proprement parler, on garde juste tous les exemples en mémoire et on calcule au moment de la prédiction.
Coût de l'algorithme
Pour classer un seul nouveau point :
- on calcule distances : ;
- on les trie : — ou on peut faire moins si on ne veut que les plus petites ;
- on fait un vote : .
Au total : par prédiction. Acceptable pour quelques milliers d'exemples, lourd au-delà — d'où des structures de données plus malines (arbres k-d, hashage de localité) qu'on rencontre en pratique réelle.
Le k-NN appartient à quelle famille d'apprentissage ?
Pièges courants
- Unités hétérogènes : si une coordonnée est en grammes (100 à 200) et l'autre en centimètres (5 à 8), le poids dominera la distance et la taille sera ignorée. On normalise souvent les coordonnées avant de calculer des distances.
- Choix de extrême : surajuste, trop grand sous-ajuste.
- Base de données déséquilibrée : si vous avez 90 % de pommes et 10 % de mandarines, le vote majoritaire prédira presque toujours « pomme ». Il faut équilibrer ou pondérer.
Pour aller plus loin
Le k-NN est conceptuellement très simple. C'est souvent un baseline — un algorithme de référence facile à coder, contre lequel on compare des méthodes plus sophistiquées (arbres de décision, réseaux de neurones, etc.). Sa simplicité reste sa force pédagogique : pour comprendre l'idée même d'apprentissage automatique, il est imbattable.