Éducation Nationale Française · ECGappliquées
Algorithmique et Python
Python est l'outil de calcul utilisé toute l'année, en lien direct avec les mathématiques du cours. Ce chapitre suit les axes annuels d'informatique : d'abord une boîte à outils Python compacte (types, structures de contrôle, fonctions, listes), puis les algorithmes sur les listes (recherche séquentielle, recherche dichotomique, méthodes gloutonnes), l'approximation numérique d'une racine, les statistiques descriptives sur des données réelles, les graphes et plus courts chemins, et enfin la simulation aléatoire. Les mathématiques sous-jacentes à chaque thème — indicateurs statistiques, suites récurrentes, matrice d'adjacence d'un graphe, lois discrètes usuelles — ont déjà été construites dans les chapitres précédents et sont seulement rappelées ici ; le contenu nouveau consiste à transformer ces mathématiques en algorithmes et à les exécuter en Python.
Conventions. Le code est écrit en Python 3 avec les bibliothèques
Conventions. Le code est écrit en Python 3 avec les bibliothèques
numpy (import numpy as np), numpy.linalg (import numpy.linalg as al), numpy.random (import numpy.random as rd), matplotlib.pyplot (import matplotlib.pyplot as plt) et pandas (import pandas as pd). Les indices de listes et de tableaux commencent à \(0\). Le code multi-lignes est présenté dans un bloc à chasse fixe ; les commandes courtes sont écrites en chasse fixe dans le texte.
I
La boîte à outils Python
I.1
Types, structures de contrôle et fonctions
Un programme manipule des variables : des boîtes nommées contenant une valeur d'un certain type (entier, flottant, booléen, chaîne de caractères). Le déroulement d'un programme est organisé par trois structures de contrôle — conditionnelle, boucle bornée, boucle non bornée — et par des fonctions qui regroupent un calcul réutilisable. Cette sous-section fixe le vocabulaire minimal ; tout ce qui suit en découle.
Définition — Variable, type et affectation
L'affectation x = v range la valeur v dans la variable x. Le type d'une valeur décrit sa nature ; les types de base courants sont int (entier), float (un réel approché, stocké en binaire fini et écrit avec un point décimal), bool (True ou False), str (chaîne de caractères) — et list, introduit ensuite. Les opérateurs arithmétiques sont +, -, *, / (résultat toujours float), ** (puissance), // (quotient entier) et \(\pourcent\) (reste), et les comparaisons ==, !=, <, >, <=, >= renvoient un bool. Les connecteurs logiques sont and, or, not. Exemple
Après a = 7 et b = 2, l'expression a \(\pourcent\) b (reste) vaut \(1\), a // b (quotient entier) vaut \(3\), a / b vaut \(3{,}5\), et a == b vaut False. Le booléen (a > 0) and (b > 0) vaut True. Méthode — Structures de contrôle
Trois structures organisent le déroulement : - conditionnelle —
if/elif/elseexécute une branche selon un test booléen ; - boucle bornée —
for k in range(n)répète un bloc pourkprenant les valeurs \(0, 1, \dots, n-1\) (le nombre de répétitions est connu à l'avance) ; - boucle non bornée —
while conditionrépète tant que la condition booléenne est vraie (le nombre de répétitions n'est pas connu à l'avance).
Exemple
Une fonction renvoyant la factorielle \(n! = 1 \times 2 \times \dots \times n\) d'un entier naturel \(n\) utilise une boucle bornée avec un accumulateur initialisé à \(1\) (ainsi \(0!\) renvoie \(1\), le produit vide) : \begin{verbatim} def factorielle(n): p = 1 for k in range(1, n + 1): p = p * k return p \end{verbatim} Appeler factorielle(5) renvoie \(120\). Le schéma « initialiser un accumulateur, le mettre à jour dans une boucle, le renvoyer » est l'outil de base de ce chapitre. Compétences à pratiquer
- Lire des expressions Python
I.2
Les listes
Une liste stocke une suite finie de valeurs, accessibles par leur indice. Les listes sont la structure de données centrale des algorithmes de ce chapitre : une série statistique, les termes successifs d'une suite, les voisins d'un sommet dans un graphe sont tous stockés sous forme de listes. Un tableau
numpy unidimensionnel joue le même rôle pour l'indexation, mais attention : sur une liste Python + concatène et * répète, alors que sur un tableau numpy les mêmes symboles agissent coefficient par coefficient (arithmétique). On utilise ici des listes ordinaires, sauf import explicite de numpy.
Définition — Liste
Une liste s'écrit entre crochets, L = [3, 1, 4, 1, 5]. L'élément d'indice i est L[i] (le premier a l'indice \(0\)) ; L[-1] est le dernier. Sa longueur est len(L). Le test d'appartenance x in L renvoie un booléen, et L.count(x) le nombre d'occurrences de x. La liste s'agrandit par L.append(x) (ajout de x à la fin) et se réduit par del L[i]. La concaténation est L + M, et la répétition k * L. Méthode — Construire une liste
Une liste de valeurs calculées se construit de deux façons équivalentes. Par une boucle avec append : \begin{verbatim} L = [] for k in range(1, 6): L.append(k * k) \end{verbatim} ou, plus compactement, par compréhension : \begin{verbatim} L = [k * k for k in range(1, 6)] \end{verbatim} les deux produisent [1, 4, 9, 16, 25]. La fonction range(a, b) parcourt \(a, a+1, \dots, b-1\). Exemple
La somme des éléments d'une liste L se calcule avec un accumulateur, sur le modèle de la factorielle : \begin{verbatim} def somme_liste(L): s = 0 for x in L: s = s + x return s \end{verbatim} Sur L = [3, 1, 4, 1, 5], elle renvoie \(14\). La boucle for x in L parcourt directement les valeurs de la liste, pas leurs indices. Compétences à pratiquer
- Manipuler des listes
II
Algorithmes sur les listes
II.1
Rechercher dans une liste
L'algorithme le plus élémentaire lit une liste une fois de gauche à droite et en rend compte : savoir si une valeur est présente, où elle se trouve, quel est le plus grand élément. Ce balayage en une passe est le prototype d'un algorithme spécifié de façon abstraite, puis traduit en Python. On ne formalise pas ici la correction ni la terminaison — ces notions ne sont pas exigées — mais on remarque au passage qu'une seule boucle
for sur une liste finie se termine toujours.
Méthode — Recherche séquentielle
Pour savoir si x est dans une liste L et à quel indice, on balaie une fois et on renvoie le premier indice correspondant, ou \(-1\) s'il est absent : \begin{verbatim} def recherche(L, x): for i in range(len(L)): if L[i] == x: return i return -1 \end{verbatim} Le return à l'intérieur de la boucle arrête le balayage dès que x est trouvé. Dans le pire cas (x absent), la boucle s'exécute len(L) fois : le coût croît linéairement avec la longueur de la liste. Exemple
Sur L = [3, 1, 4, 1, 5], l'appel recherche(L, 4) renvoie \(2\) (l'indice du premier \(4\)), et recherche(L, 9) renvoie \(-1\). L'appel recherche(L, 1) renvoie \(1\), l'indice de la première occurrence. Méthode — Maximum et second maximum
Le maximum d'une liste non vide se trouve en conservant une meilleure valeur courante, mise à jour à chaque étape : \begin{verbatim} def maximum(L): m = L[0] for x in L: if x > m: m = x return m \end{verbatim} Pour obtenir le second maximum (la plus grande valeur strictement inférieure au maximum, sur une liste ayant au moins deux valeurs distinctes) en une passe, on conserve deux valeurs m1 (le meilleur) et m2 (le deuxième), toutes deux initialisées à \(-\infty\) (en Python, float("-inf")). Pour chaque valeur x : si x est égale à m1, on l'ignore (c'est un doublon du maximum) ; sinon, si x > m1, l'ancien m1 devient le nouveau m2 et m1 devient x ; sinon, si x > m2, on met à jour m2 seul. Ignorer les doublons de m1 garantit que m2 termine sur la deuxième valeur distincte, même quand le maximum apparaît plusieurs fois. Exemple
Le plus petit écart entre deux valeurs d'une liste se trouve en comparant toutes les paires, par une double boucle (elle renvoie la distance minimale ; les deux valeurs qui la réalisent pourraient être suivies en parallèle) : \begin{verbatim} def deux_plus_proches(L): best = abs(L[0] - L[1]) for i in range(len(L)): for j in range(i + 1, len(L)): d = abs(L[i] - L[j]) if d < best: best = d return best \end{verbatim} Sur L = [3, 1, 4, 1, 5], les deux \(1\) égaux donnent l'écart minimal \(0\) (la liste est supposée de longueur au moins \(2\)). Deux boucles imbriquées coûtent environ \(n^2/2\) comparaisons sur une liste de longueur \(n\). Compétences à pratiquer
- Rechercher dans une liste
II.2
Recherche dichotomique
Lorsque la liste est triée par ordre croissant, une recherche bien plus rapide est possible : à chaque étape, on compare la cible à l'élément du milieu et on élimine la moitié de la plage restante. Cette division par deux est la même idée que la méthode de dichotomie pour les équations, à la section suivante. Le nombre d'étapes est d'ordre \(\log_2 n\) au lieu de \(n\).
Méthode — Recherche dichotomique dans une liste triée
On maintient une fenêtre [g, d] d'indices candidats, d'abord la liste entière, et on la divise par deux à chaque étape : \begin{verbatim} def recherche_dicho(L, x): g, d = 0, len(L) - 1 while g <= d: m = (g + d) // 2 if L[m] == x: return m elif L[m] < x: g = m + 1 else: d = m - 1 return -1 \end{verbatim} À chaque tour, la largeur d - g est au moins divisée par deux, donc la boucle s'exécute au plus environ \(\log_2(\texttt{len(L)})\) fois avant que g > d : cela garantit la terminaison sur une liste finie. Exemple
Sur la liste triée L = [2, 3, 5, 7, 11, 13, 17] (longueur \(7\)), recherche de \(11\) : la fenêtre est \([0, 6]\), l'indice milieu \(3\) contient \(7 < 11\), donc la fenêtre devient \([4, 6]\) ; l'indice milieu \(5\) contient \(13 > 11\), donc la fenêtre devient \([4, 4]\) ; l'indice milieu \(4\) contient \(11\) — trouvé à l'indice \(4\) en trois comparaisons, contre jusqu'à sept pour un balayage séquentiel. Compétences à pratiquer
- Dérouler une recherche dichotomique
II.3
Algorithmes gloutons
Un algorithme glouton construit une solution étape par étape, en faisant à chaque étape le choix qui paraît le meilleur sur le moment, sans jamais le remettre en cause. Il est simple et rapide ; sur certains problèmes il fournit même une solution optimale, sur d'autres seulement une solution approchée. On illustre le principe sur deux problèmes classiques et on en reste au niveau de la méthode, sans preuve d'optimalité.
Définition — Principe glouton
Un algorithme glouton construit une solution comme une suite de choix locaux irrévocables : à chaque étape, parmi les options admissibles, il choisit celle qui optimise un critère immédiat, puis passe à la suite sans retour en arrière. Méthode — Rendu de monnaie
Pour payer un montant n avec des valeurs de pièces listées par ordre décroissant, on prend à plusieurs reprises autant d'exemplaires que possible de la plus grande pièce ne dépassant pas le montant restant : \begin{verbatim} def rendu(n, pieces): resultat = [] for c in pieces: # pieces en ordre decroissant while n >= c: resultat.append(c) n = n - c return resultat \end{verbatim} Avec le système canonique pieces = [50, 20, 10, 5, 2, 1] (en centimes), le choix glouton est optimal (le moins de pièces) ; pour un système quelconque il peut ne pas l'être — par exemple avec [4, 3, 1] et n = 6, le glouton donne \(4 + 1 + 1\) (trois pièces) alors que \(3 + 3\) n'en utilise que deux. Exemple
Allouer un nombre maximal de cours sans chevauchement à une seule salle est un autre problème glouton. Chaque cours est un intervalle semi-ouvert \([\text{début}, \text{fin})\), de sorte que deux cours partageant seulement une extrémité (l'un finit à l'instant où l'autre commence) ne se chevauchent pas. La règle est : trier les cours par heure de fin croissante, puis prendre chaque cours dont le début n'est pas antérieur à la fin du dernier cours retenu. Sur les cours \([9, 10)\), \([9, 12)\), \([10, 11)\), \([11, 13)\), le tri par heure de fin donne \([9, 10)\), \([10, 11)\), \([9, 12)\), \([11, 13)\) ; le choix glouton retient \([9, 10)\), puis \([10, 11)\), puis \([11, 13)\) — trois cours, le maximum possible. Compétences à pratiquer
- Appliquer un algorithme glouton
III
Approximation numérique
III.1
Méthode de dichotomie
Pour approcher une racine d'une équation \(f(x) = 0\) lorsqu'aucune forme close n'est disponible, la méthode de dichotomie transforme le théorème des valeurs intermédiaires (rappelé du chapitre Limites et continuité) en algorithme : si \(f\) est continue et change de signe sur \([a, b]\), elle y admet une racine ; diviser l'intervalle par deux à chaque étape enferme la racine dans un intervalle dont la largeur est divisée par deux à chaque fois.
Méthode — Dichotomie pour f(x)\(\equal\)0
On suppose \(f\) continue sur \([a, b]\) avec \(f(a)\) et \(f(b)\) de signes opposés. On divise par deux l'intervalle d'encadrement jusqu'à ce que sa largeur passe sous une tolérance eps : \begin{verbatim} def dichotomie(f, a, b, eps): while b - a > eps: m = (a + b) / 2 if f(a) * f(m) <= 0: b = m else: a = m return (a + b) / 2 \end{verbatim} Le test f(a) * f(m) <= 0 conserve la demi-portion sur laquelle le changement de signe persiste. Après \(k\) étapes la largeur vaut \((b - a)/2^k\), donc atteindre la tolérance eps demande environ \(\log_2\!\bigl((b-a)/\texttt{eps}\bigr)\) étapes. Exemple
Prenons \(f(x) = x^2 - 2\) sur \([1, 2]\) : \(f(1) = -1 < 0\) et \(f(2) = 2 > 0\), donc \(f\) a une racine dans \([1, 2]\), à savoir \(\sqrt{2}\). En définissant f par def f(x): return x**2 - 2 et en appelant dichotomie(f, 1, 2, 1e-6), on obtient une valeur à \(10^{-6}\) près de \(\sqrt{2} \approx 1{,}414214\). La première étape prend \(m = 1{,}5\), avec \(f(1{,}5) = 0{,}25 > 0\), donc l'intervalle devient \([1\,;\,1{,}5]\). Compétences à pratiquer
- Approcher par dichotomie
III.2
Approximation par suite récurrente
Une deuxième voie vers une solution numérique utilise une suite récurrente \(u_{n+1} = g(u_n)\) (rappelée du chapitre Suites réelles usuelles) : lorsque la suite converge vers \(\ell\) et que \(g\) est continue en \(\ell\), le passage à la limite dans \(u_{n+1} = g(u_n)\) donne \(\ell = g(\ell)\), donc itérer \(g\) approche une solution de \(x = g(x)\). La boucle tourne jusqu'à ce que deux termes consécutifs soient plus proches qu'un seuil.
Méthode — Itération de point fixe avec seuil
On itère \(u \leftarrow g(u)\) à partir d'une valeur initiale u0, en s'arrêtant quand la mise à jour déplace la valeur de moins de eps : \begin{verbatim} def point_fixe(g, u0, eps): u = u0 v = g(u) while abs(v - u) > eps: u = v v = g(u) return v \end{verbatim} Le test d'arrêt abs(v - u) > eps compare deux termes consécutifs ; il ne doit être utilisé que lorsqu'on sait, par une étude mathématique préalable, que la suite converge. Un petit écart entre deux termes consécutifs est un signal d'arrêt pratique, et non une garantie que la valeur renvoyée soit à eps près du vrai point fixe — c'est l'étude préalable qui justifie de s'y fier. Exemple
L'itération de Héron pour \(\sqrt{a}\) utilise \(g(u) = \frac{1}{2}\bigl(u + \frac{a}{u}\bigr)\), dont le point fixe résout \(u = \frac{a}{u}\), c'est-à-dire \(u^2 = a\). Pour \(a = 2\), u0 = 2, l'itération donne \(1{,}5\), puis \(1{,}41\overline{6}\), puis \(1{,}414215\dots\), convergeant vers \(\sqrt{2}\) très vite (le nombre de décimales correctes double à peu près à chaque étape). En définissant g par def g(u): return (u + 2/u)/2 et en appelant point_fixe(g, 2, 1e-6), l'itération s'arrête dès que deux termes consécutifs coïncident à \(10^{-6}\) près et renvoie une valeur égale à \(\sqrt{2}\) à autant de décimales (c'est la convergence très rapide, établie par une étude préalable, qui rend la valeur renvoyée fiable ici). Compétences à pratiquer
- Approcher par une suite récurrente
IV
Statistiques descriptives et données
IV.1
Lire et décrire des données
Les données statistiques publiques (de data.gouv ou de l'Insee) se présentent souvent sous la forme d'un fichier de valeurs séparées par des virgules (
csv). La bibliothèque pandas lit un tel fichier dans une table et calcule les indicateurs de position et de dispersion du chapitre Statistiques univariées — moyenne, médiane, mode, quantiles, étendue, variance, écart-type — directement sur les colonnes. Aucune de ces commandes n'est une connaissance exigible ; on les utilise avec leur documentation sous les yeux.
Méthode — L'inventaire des commandes pandas
Avec import pandas as pd et une table df = pd.read_csv("data.csv") : -
df.head()— les premières lignes ;df.shape— le couple (lignes, colonnes) ; -
df.describe()— un résumé (effectif, moyenne, écart-type, min, quartiles, max) de chaque colonne numérique ; -
df["age"].mean(),.median(),.std(),.count()— les indicateurs d'une colonne ; -
df.sort_values("age")— la table triée selon la colonne"age".
.var() et .std() divisent par \(N - 1\) par défaut, alors que Statistiques univariées divise la variance empirique par \(N\) (pour retrouver la valeur du cours, on passe l'option ddof=0, par exemple df["age"].std(ddof=0)) ; et les quartiles renvoyés par describe ou .quantile() utilisent une convention d'interpolation qui peut différer de celle du cours, donc sur de petits échantillons ils peuvent ne pas coïncider exactement avec les quartiles calculés à la main. Exemple
Sur une petite série d'âges [18, 19, 19, 20, 24] rangée dans une colonne df["age"], l'appel df["age"].mean() renvoie \(20\), df["age"].median() renvoie \(19\), et df["age"].count() renvoie \(5\). On retrouve, sur la colonne, les indicateurs calculés à la main dans Statistiques univariées. Compétences à pratiquer
- Décrire des données avec pandas
IV.2
Visualiser des données
La bibliothèque
matplotlib.pyplot dessine les données. Un diagramme en bâtons montre une distribution discrète, un histogramme regroupe des données continues en classes, une boîte à moustaches résume une série par ses quartiles. Comme pour pandas, ces commandes s'utilisent avec leur documentation ; aucune n'est une connaissance exigible.
Méthode — L'inventaire des commandes matplotlib
Avec import matplotlib.pyplot as plt : -
plt.plot(x, y)puisplt.show()— une courbe passant par les points \((x_i, y_i)\) (graphes de fonctions, termes d'une suite) ; -
plt.bar(x, h)— un diagramme en bâtons de hauteurshaux positionsx; -
plt.hist(data)— un histogramme des valeurs dedata; -
plt.boxplot(data)— une boîte à moustaches (quartiles) dedata.
plt.show(). Exemple
Pour tracer le diagramme en bâtons des effectifs observés des faces d'un dé, avec les positions \(1, \dots, 6\) et les effectifs h : \begin{verbatim} import matplotlib.pyplot as plt x = [1, 2, 3, 4, 5, 6] h = [18, 22, 17, 20, 23, 20] plt.bar(x, h) plt.show() \end{verbatim} Les bâtons les plus hauts sont les faces les plus fréquentes ; sur un dé équilibré, les six hauteurs sont proches. Compétences à pratiquer
- Visualiser des données
V
Graphes et plus courts chemins
V.1
Représenter un graphe en Python
Un graphe fini (rappelé du chapitre Graphes) se stocke en Python de deux façons : par sa matrice d'adjacence — un tableau
numpy de \(0\) et de \(1\) — ou par des listes d'adjacence — pour chaque sommet, la liste de ses voisins, rassemblées dans une liste ou un dictionnaire. La forme matricielle se relie directement au calcul matriciel déjà étudié ; la forme par listes est plus légère quand le graphe a peu d'arêtes.
Définition — Représentation par listes d'adjacence
La représentation par listes d'adjacence d'un graphe sur les sommets \(0, \dots, n-1\) stocke, pour chaque sommet i, la liste adj[i] des sommets adjacents à i. Le graphe entier est alors la liste de listes adj (ou un dictionnaire associant à chaque sommet sa liste de voisins). Pour un graphe pondéré, chaque voisin est stocké avec le poids de l'arête qui le relie, sous forme de couple. Exemple
Le triangle sur les sommets \(0, 1, 2\) dont les trois arêtes sont présentes a pour matrice d'adjacence et listes d'adjacence $$A = \begin{pmatrix} 0 & 1 & 1 \\
1 & 0 & 1 \\
1 & 1 & 0 \end{pmatrix}, \qquad \texttt{adj} = [[1, 2],\ [0, 2],\ [0, 1]].$$ Lecture de la matrice : adj[i] est la liste des indices de colonnes j tels que \(A[i][j] = 1\). En Python, A = np.array([[0,1,1],[1,0,1],[1,1,0]]). Compétences à pratiquer
- Représenter un graphe
V.2
L'algorithme de Dijkstra
Sur un graphe dont les arêtes portent des poids positifs, le plus court chemin d'un sommet source vers chaque autre sommet est trouvé par l'algorithme de Dijkstra. Il est glouton : il fait croître un ensemble de sommets fixés dont la distance minimale est connue, en fixant à chaque étape le sommet non fixé de plus petite distance provisoire et en relâchant ses arêtes sortantes. C'est la positivité des poids qui rend le choix glouton correct.
Méthode — L'algorithme de Dijkstra
Le graphe est donné par listes d'adjacence pondérées : adj[i] est une liste de couples (j, w) signifiant une arête de i vers j de poids w. Les distances valent \(+\infty\) au départ, sauf la source à \(0\) : \begin{verbatim} import numpy as np def dijkstra(adj, source): n = len(adj) dist = [np.inf] * n dist[source] = 0 fixe = [False] * n for _ in range(n): # choisir le sommet non fixe le plus proche u, best = -1, np.inf for i in range(n): if not fixe[i] and dist[i] < best: u, best = i, dist[i] if u == -1: break fixe[u] = True for (j, w) in adj[u]: # relacher les aretes issues de u if dist[u] + w < dist[j]: dist[j] = dist[u] + w return dist \end{verbatim} La liste renvoyée dist contient la distance minimale de la source à chaque sommet. Pour récupérer le chemin lui-même — et pas seulement sa longueur — on stocke, à chaque relâchement, le prédécesseur du sommet amélioré dans une liste séparée et on le remonte depuis la cible ; on ne conserve ici que les distances. Chaque étape externe fixe un sommet (ou s'arrête plus tôt dès que les sommets non fixés sont inatteignables), donc l'algorithme s'arrête après au plus \(n\) étapes. Exemple
Prenons les sommets \(0, 1, 2, 3\) avec les arêtes de poids positif \(0\!-\!1\) (\(1\)), \(0\!-\!2\) (\(4\)), \(1\!-\!2\) (\(2\)), \(2\!-\!3\) (\(1\)) ; le graphe étant non orienté, chaque arête est stockée dans les deux listes d'adjacence adj[i] et adj[j]. Depuis la source \(0\) : on fixe \(0\) (distance \(0\)) ; le plus proche non fixé est \(1\) (distance \(1\)), qui relâche \(2\) à \(1 + 2 = 3\) (mieux que \(4\)) ; on fixe \(2\) (distance \(3\)), qui relâche \(3\) à \(3 + 1 = 4\) ; on fixe \(3\) (distance \(4\)). Les distances minimales sont [0, 1, 3, 4], le chemin vers \(3\) étant \(0 \to 1 \to 2 \to 3\). Compétences à pratiquer
- Dérouler Dijkstra
VI
Simuler des phénomènes aléatoires
VI.1
La bibliothèque numpy.random
On simule une expérience aléatoire en Python avec la bibliothèque
numpy.random. Sa brique de base est rd.random(), un nombre tiré uniformément au hasard dans \([0, 1[\). À partir d'elle, on construit une épreuve de Bernoulli de paramètre \(p\) (succès lorsque le tirage est inférieur à \(p\)), et par répétition un comptage binomial (rappelé du chapitre Lois discrètes usuelles). En répétant une simulation un grand nombre de fois, la fréquence observée d'un événement approche sa probabilité.
Méthode — Bernoulli et binomiale à partir de rd.random
Une épreuve de Bernoulli de paramètre \(p \in [0, 1]\) renvoie \(1\) (succès) avec probabilité \(p\), en comparant un tirage uniforme à \(p\) ; en sommant \(n\) épreuves indépendantes, on obtient un comptage binomial \(\mathcal{B}(n, p)\) : \begin{verbatim} import numpy.random as rd def bernoulli(p): if rd.random() < p: return 1 return 0 def binomiale(n, p): s = 0 for k in range(n): s = s + bernoulli(p) return s \end{verbatim} La condition rd.random() < p est vraie avec probabilité exactement \(p\), puisque le tirage est uniforme sur \([0, 1[\). Exemple
Pour vérifier expérimentalement qu'une épreuve de Bernoulli de paramètre \(p = 0{,}3\) a une fréquence de succès proche de \(0{,}3\), on la répète de nombreuses fois et on fait la moyenne : \begin{verbatim} N = 100000 s = 0 for k in range(N): s = s + bernoulli(0.3) print(s / N) # proche de 0.3 \end{verbatim} Pour \(N = 10^5\), la fréquence affichée vaut typiquement \(0{,}30\) à deux décimales — une illustration de la convergence de la fréquence vers la probabilité. Compétences à pratiquer
- Simuler avec numpy.random
VI.2
Échantillonner des lois usuelles
La bibliothèque
numpy.random tire aussi directement selon les lois usuelles, sans les reconstruire à partir de rd.random. Ces générateurs prêts à l'emploi renvoient une seule valeur, ou bien un vecteur ou une matrice entière de tirages indépendants, ce qui est commode pour produire un échantillon d'un coup, puis en tracer l'histogramme.
Méthode — Générateurs directs
Avec import numpy.random as rd, les lois usuelles du chapitre Lois discrètes usuelles se tirent par : -
rd.randint(a, b)— un entier uniforme dans \(\{a, \dots, b-1\}\) ; -
rd.binomial(n, p)— un tirage selon \(\mathcal{B}(n, p)\) ; -
rd.geometric(p)— un tirage selon la loi géométrique de paramètre \(p\) (rang du premier succès) ; -
rd.poisson(lam)— un tirage selon la loi de Poisson de paramètrelam.
rd.binomial(10, 0{,}2, 100) renvoie un vecteur de \(100\) tirages indépendants selon \(\mathcal{B}(10\,;\,0{,}2)\). Exemple
Pour tracer l'histogramme d'un échantillon binomial et le comparer à la forme théorique : \begin{verbatim} import numpy.random as rd import matplotlib.pyplot as plt echantillon = rd.binomial(10, 0.5, 10000) plt.hist(echantillon) plt.show() \end{verbatim} L'histogramme est en cloche et centré près de \(np = 5\), l'espérance de \(\mathcal{B}(10, 0{,}5)\) calculée dans Lois discrètes usuelles.
Pour aller plus loin
Les algorithmes présentés ici en restent au niveau de la méthode et de la traduction ; leur correction et leur terminaison, ainsi que l'étude systématique de leur coût (complexité), sont formalisées plus tard. L'algorithmique de deuxième année revisite plus en profondeur les graphes et la simulation ; la loi de Poisson, rencontrée dans Lois discrètes usuelles et utilisée ci-dessus comme générateur prêt à l'emploi, y sera revue comme limite de lois binomiales (convergence en loi) dans les chapitres de probabilités de deuxième année. Les mathématiques rappelées tout au long de ce chapitre — indicateurs statistiques, suites récurrentes, matrice d'adjacence, lois binomiale, géométrique et de Poisson — vivent dans les chapitres Statistiques univariées, Suites réelles usuelles, Graphes et Lois discrètes usuelles.
Compétences à pratiquer
- Échantillonner une loi usuelle
VII
Pour aller plus loin
Compétences à pratiquer
- Combiner algorithme et Python
Aller à la section