k plus proches voisins, dichotomie et gloutons
Tu ouvres une application de musique : elle te propose un morceau « qui ressemble » à ceux que tu aimes. Tu cherches un nom dans un annuaire de 1 000 pages : tu ne lis pas tout. Une caissière rend la monnaie en prenant toujours le plus gros billet possible. Trois situations, trois algorithmes : les k plus proches voisins, la dichotomie et les algorithmes gloutons. À la fin, on se demandera pourquoi la caissière a de la chance.
Les k plus proches voisins
Un jeu de données contient des éléments dont on connaît la classe (ici, l'espèce d'une fleur). On reçoit un nouvel élément inconnu : on veut prédire sa classe. L'idée : il ressemble à ses voisins.
Chaque élément est un point du plan, par exemple (longueur ; largeur) d'un pétale. La ressemblance se mesure par la distance euclidienne :
$$d(A, B) = \sqrt{(x_B - x_A)^2 + (y_B - y_A)^2}$$En Python, on trie une liste de couples (distance, classe) :
from math import sqrt
def distance(p, q):
return sqrt((p[0] - q[0]) ** 2 + (p[1] - q[1]) ** 2)
def voisins(donnees, p, k):
# donnees : liste de triplets (x, y, classe)
liste = [(distance((x, y), p), c) for (x, y, c) in donnees]
liste.sort()
return liste[:k]
Dans le plan, on considère les points A(1 ; 2) et B(4 ; 6). a) Calculer la distance euclidienne $d(A, B)$. b) Donner la formule de la distance euclidienne entre…
Dans le plan, on considère les points A(1 ; 2) et B(4 ; 6).
- a) Calculer la distance euclidienne $d(A, B)$.
- b) Donner la formule de la distance euclidienne entre $(x_1, y_1)$ et $(x_2, y_2)$.
- c) Parmi les points C(2 ; 2) et D(5 ; 5), lequel est le plus proche de A ?
Un jeu de données classe des fleurs en deux espèces, A et B, d'après la longueur et la largeur de leurs pétales (en cm) : (1,0 ; 0,5) : A (1,5 ; 0,4) : A (4,5 ; 1,5) : B…
Un jeu de données classe des fleurs en deux espèces, A et B, d'après la longueur et la largeur de leurs pétales (en cm) :
-
(1,0 ; 0,5) : A
-
(1,5 ; 0,4) : A
-
(4,5 ; 1,5) : B
-
(5,0 ; 1,8) : B
-
(4,0 ; 1,2) : B
- a) Calculer la distance de chaque donnée à la fleur inconnue (2,0 ; 0,6).
- b) Appliquer l'algorithme des $k$ plus proches voisins avec $k = 3$ et donner l'espèce prédite.
- c) Écrire une fonction Python qui renvoie les $k$ plus proches voisins d'un point.
Une table contient des relevés de températures et d'humidité pour des journées classées « pluie » ou « sec » dans une ville de Bretagne. On souhaite prédire la classe…
Une table contient des relevés de températures et d'humidité pour des journées classées « pluie » ou « sec » dans une ville de Bretagne. On souhaite prédire la classe d'une nouvelle journée par $k$ plus proches voisins.
- a) Expliquer pourquoi il peut être nécessaire de normaliser les données avant de calculer les distances lorsque les deux attributs n'ont pas la même échelle.
- b) Écrire une fonction
knn(donnees, p, k)qui renvoie la classe majoritaire parmi les $k$ voisins les plus proches dep, oùdonneesest une liste de triplets(x, y, classe).
- c) Discuter l'effet du choix de $k$ (trop petit, trop grand) sur la prédiction, et donner la complexité de la fonction en fonction de la taille $n$ des données.
La recherche dichotomique
Pour trouver un mot dans un dictionnaire, tu l'ouvres au milieu, puis tu gardes la moitié utile. C'est la dichotomie : elle exige un tableau trié.
def dichotomie(t, x):
debut, fin = 0, len(t) - 1
while debut <= fin:
milieu = (debut + fin) // 2
if t[milieu] == x:
return True
elif t[milieu] < x:
debut = milieu + 1
else:
fin = milieu - 1
return False
À chaque tour, la zone de recherche est divisée par 2. Pour $n$ éléments, il faut au plus $\lfloor \log_2 n \rfloor + 1$ tours : environ 10 pour 1 000 éléments, environ 20 pour un million. Une recherche séquentielle en demanderait 1 000, ou un million.
On recherche par dichotomie la valeur 23 dans le tableau trié [3, 8, 12, 17, 23, 29, 35, 41] (indices de 0 à 7). a) Donner les valeurs successives des indices debut, fin…
On recherche par dichotomie la valeur 23 dans le tableau trié [3, 8, 12, 17, 23, 29, 35, 41] (indices de 0 à 7).
- a) Donner les valeurs successives des indices
debut,finetmilieu(avecmilieu = (debut + fin) // 2).
- b) Combien de valeurs du tableau sont comparées à 23 au cours de la recherche ?
Écrire une fonction dichotomie(t, x) qui renvoie True si x appartient au tableau trié t, False sinon. a) Écrire la fonction avec une boucle while debut <= fin. b)…
Écrire une fonction dichotomie(t, x) qui renvoie True si x appartient au tableau trié t, False sinon.
- a) Écrire la fonction avec une boucle
while debut <= fin.
- b) Indiquer le variant de la boucle.
- c) Combien de tours de boucle au maximum pour un tableau de 1 000 éléments ?
Variant et invariant
Comment être sûr que l'algorithme s'arrête et qu'il est correct ?
Pour la dichotomie :
On reprend la fonction dichotomie ci-dessus (dans certains énoncés, debut, fin et milieu sont notés d, f et m, et la fonction renvoie l'indice trouvé ou -1 au lieu de True ou False : le raisonnement est le même).
-
Variant :
fin - debut + 1, la taille de la zone de recherche. Tant quedebut <= fin, elle est $\geq 1$. À chaque tour,debutaugmente oufindiminue d'au moins 1 : elle décroît strictement. Elle ne peut pas décroître indéfiniment : la boucle se termine. -
Invariant : « si
xest danst, son indice est entredebutetfin». C'est vrai au début (debut = 0,fin = len(t) - 1). Sit[milieu] < x, commetest trié, les indices $\leq$milieune conviennent pas :debut = milieu + 1conserve la propriété. Même raisonnement pourt[milieu] > xavecfin = milieu - 1. -
Sortie : si
debut > fin, la zone est vide, doncxn'est pas danst: renvoyerFalse(ou-1dans la version qui renvoie un indice) est correct.
Prouver ainsi la correction avec un invariant est essentiel : un jeu de tests ne suffit pas à garantir qu'un programme est correct. La preuve complète de correction peut être présentée par ton professeur ; retiens le principe.
Soit l'algorithme de recherche dichotomique suivant dans un tableau trié t de n éléments : a) Montrer que la quantité $f - d + 1$ est un variant de la boucle et en…
Soit l'algorithme de recherche dichotomique suivant dans un tableau trié t de n éléments :
def recherche(t, x):
d, f = 0, len(t) - 1
while d <= f:
m = (d + f) // 2
if t[m] == x:
return m
elif t[m] < x:
d = m + 1
else:
f = m - 1
return -1
- a) Montrer que la quantité $f - d + 1$ est un variant de la boucle et en déduire la terminaison.
- b) Énoncer un invariant : si
xest danst, alors son indice est compris entredetf. Le démontrer.
- c) Montrer que le nombre de tours est au plus $\lfloor \log_2 n \rfloor + 1$.
Les algorithmes gloutons
Un algorithme glouton construit une solution étape par étape, en faisant à chaque fois le choix qui semble le meilleur sur le moment, sans jamais revenir en arrière.
Exemple classique, le rendu de monnaie : rendre la somme avec le moins de pièces et billets.
def rendu(somme, systeme):
# systeme trié par valeurs décroissantes
resultat = []
for valeur in systeme:
while somme >= valeur:
resultat.append(valeur)
somme -= valeur
return resultat
Autre problème : le sac à dos. On choisit des objets de masse et de valeur donnés, sans dépasser la capacité, pour maximiser la valeur. Plusieurs critères gloutons sont possibles : par valeur décroissante, par masse croissante, ou par rapport valeur/masse décroissant. Ils ne donnent pas toujours le même résultat.
On doit rendre 63 € avec des pièces et billets de 50 €, 20 €, 10 €, 5 €, 2 € et 1 €. a) Appliquer l'algorithme glouton de rendu de monnaie et donner la composition du…
On doit rendre 63 € avec des pièces et billets de 50 €, 20 €, 10 €, 5 €, 2 € et 1 €.
- a) Appliquer l'algorithme glouton de rendu de monnaie et donner la composition du rendu.
- b) Combien de pièces et billets sont utilisés ?
Un sac à dos de capacité 15 kg doit contenir des objets de valeur maximale. Objets (masse en kg ; valeur en €) : A (12 ; 4), B (2 ; 2), C (1 ; 1), D (1 ; 2), E (4 ; 10).…
Un sac à dos de capacité 15 kg doit contenir des objets de valeur maximale. Objets (masse en kg ; valeur en €) : A (12 ; 4), B (2 ; 2), C (1 ; 1), D (1 ; 2), E (4 ; 10).
- a) Appliquer l'algorithme glouton qui choisit les objets par valeur décroissante, sans fractionner les objets.
- b) Appliquer l'algorithme glouton qui choisit par rapport valeur/masse décroissant.
- c) Comparer les deux résultats.
On considère le système de monnaie $\{1, 3, 4\}$ (en unités quelconques). a) Appliquer l'algorithme glouton pour rendre 6. Donner la solution obtenue. b) Trouver une…
On considère le système de monnaie $\{1, 3, 4\}$ (en unités quelconques).
- a) Appliquer l'algorithme glouton pour rendre 6. Donner la solution obtenue.
- b) Trouver une solution utilisant moins de pièces. Conclure sur l'optimalité de l'algorithme glouton.
- c) Vérifier que le glouton est optimal pour le système $\{1, 2, 5, 10, 20, 50\}$ pour toutes les sommes jusqu'à 20, en justifiant avec un raisonnement général sur le choix de la plus grande pièce.
Retour au début : la caissière a de la « chance » parce que le système en euros est tel que le choix glouton (le plus gros billet possible) donne toujours un rendu optimal.
L'essentiel
-
k plus proches voisins : calculer les distances, garder les $k$ plus petites, prédire la classe majoritaire. Normaliser si les échelles diffèrent ; le choix de $k$ compte.
-
Dichotomie : sur un tableau trié, on coupe la zone en deux à chaque tour ; au plus $\lfloor \log_2 n \rfloor + 1$ tours.
-
Variant : quantité entière qui décroît strictement, preuve de terminaison (ici
fin - debut + 1). Invariant : propriété conservée à chaque tour, preuve de correction. -
Glouton : meilleur choix local à chaque étape, sans retour en arrière. Rapide, mais pas toujours optimal : un contre-exemple suffit à le montrer.