Introduction :
Dans cette fiche, nous allons illustrer un schéma de Bernoulli, avec un algorithme simulant une « planche de Galton ».
Après avoir expliqué en quoi consiste cette planche et montré le lien avec la loi binomiale, nous programmerons étape par étape l’algorithme en Python.
Planche de Galton et schéma de Bernoulli
Planche de Galton et schéma de Bernoulli
Principe de la planche de Galton
Principe de la planche de Galton
La planche de Galton fut inventée par le statisticien – entre autres choses – Francis Galton (1822-1911), afin d’illustrer un schéma de Bernoulli.
Il s’agit d’une planche verticale, sur laquelle sont plantés plusieurs rangées de clous (voir exemple infra).
On lâche une bille en haut : celle-ci rencontre un clou sur chaque rangée et, à chaque fois, elle va à gauche ou à droite du clou, avec une probabilité de $0,5$ pour les deux options.
Enfin, un réservoir numéroté, en bas de la planche, recueille la bille.
- Représentons cette planche, avec $4$ rangées de clous (points bleus) et donc $5$ réservoirs (de manière générale, s’il y a $n$ rangées de clous, il y a $n+1$ réservoirs) :
Cette représentation n’est pas l’échelle
L’idée est de lancer un grand nombre de billes, puis de compter le nombre de billes contenues dans chaque réservoir, avant de calculer les fréquences correspondantes.
Schéma de Bernoulli et loi binomiale
Schéma de Bernoulli et loi binomiale
Prenons une planche de Galton de $n$ rangées de clous ($n\in \mathbb N ^*$).
La bille rencontre le premier clou : elle passe à gauche avec une probabilité de $0,5$, à droite avec la même probabilité. Nous considérons que, si la bille passe à droite, c’est un succès ; un échec si elle passe à gauche.
- Nous reconnaissons une épreuve de Bernoulli, de paramètre $p=0,5$.
Il en va de même pour chaque clou rencontré ensuite sur les $n$ rangées : les probabilités que la bille passe à gauche ou à droite ne dépendent pas du clou de la rangée précédente et restent toujours égales à $0,5$.
- Il s’agit donc d’un schéma de Bernoulli, de paramètres $n$ et $p=0,5$.
Soit $X$ la variable aléatoire qui compte le nombre de succès, c’est-à-dire le nombre de fois que la bille passe à droite d’un clou.
- $X$ suit une loi binomiale de paramètres $n$ et $p=0,5$.
Si nous reprenons l’exemple de la planche avec $4$ rangées, nous voyons que :
- si la bille va $\red 0$ fois à droite, elle finit dans le réservoir $\red 0$ ;
- si elle va $\green 1$ fois à droite – peu importe à quelle rangée –, elle finit dans le réservoir $\green 1$ ;
- si elle va $\purple 2$ fois à droite – peu importe à quelles rangées –, elle finit dans le réservoir $\purple 2$ ;
- si elle va $\blue 3$ fois à droite – peu importe à quelles rangées –, elle finit dans le réservoir $\blue 3$ ;
- si elle va $\textcolor{#FFA500} 4$ fois à droite, elle finit dans le réservoir $\textcolor{#FFA500} 4$.
- Ainsi, de manière générale, $X$ donne aussi le numéro du réservoir qui recueille la bille.
Donnons la loi de probabilité de $X$, en utilisant la formule que nous avons apprise.
- Pour tout $k\in \lbrace 0,\,1,\,2,\,3,\,4\rbrace $ :
$$\begin{aligned} p(X=k)&=\begin{pmatrix} 4 \\ k \end{pmatrix}\times 0,5^k\times 0,5^{4-k} \\ &=\begin{pmatrix} 4 \\ k \end{pmatrix} \times 0,5^4 \end{aligned}$$
$k$ | $0$ | $1$ | $2$ | $3$ | $4$ |
$p(X=k)$ | $0,0625$ | $0,25$ | $0,375$ | $0,25$ | $0,0625$ |
Nous pouvons bien sûr aussi utiliser une calculatrice ou un tableur pour calculer ces différentes probabilités.
Simulation de la planche de Galton par un algorithme Python
Simulation de la planche de Galton par un algorithme Python
Préambule
Préambule
Pour simuler la direction aléatoire que prend la bile à chaque clou, nous nous servirons de la fonction $\purple{\text{randint(p, q)}}$ ($\purple{\text{p}}$ et $\purple{\text{q}}$ des entiers tels que $\purple{\text{p}} < \purple{\text{q}}$), qui fait partie du module $\purple{\text{random}}$.
- Cette fonction renvoie de manière aléatoire un nombre entier compris entre $\purple{\text{p}}$ et $\purple{\text{q}}$ inclus.
Nous donnerons le nombre de billes présentes dans chaque réservoir sous la forme d’une liste : l’élément $0$ de la liste donnera le nombre de billes présentes dans le réservoir $0$ ; l’élément $1$ celui dans le réservoir $1$, etc.
Algorithme
Algorithme
- Nous commençons par importer la fonction $\purple{\text{randint}}$ du module $\purple{\text{random}}$, puisque nous allons en avoir besoin :
$\textcolor{#A9A9A9}{\text{1}}\quad\text{from random import randint}$ |
- Nous définissons notre fonction Python $\purple{\text{galton}}$ qui simule la planche de Galton. Nous souhaitons pouvoir choisir le nombre de rangées de clous $\purple{\text{n}}$ et le nombre de billes à lâcher $\purple{\text{b}}$.
- La fonction prend donc ces données en paramètres.
$\textcolor{#A9A9A9}{\text{3}}\quad\text{def galton(n,b):}$ |
- Nous créons la liste $\purple{\text{R}}$, qui donnera le nombre de billes présentes dans chaque réservoir après les $\purple{\text{b}}$ lâchers.
Nous l’avons vu plus haut, s’il y a $\purple{\text{n}}$ rangées de clous, il y a $\purple{\text{n + 1}}$ réservoirs.
- La liste est donc de longueur $\purple{\text{n + 1}}$, nous l’initialisons bien sûr avec $\purple{\text{0}}$ bille dans chacun des réservoirs.
$\textcolor{#A9A9A9}{\text{4}}\quad\qquad\text{R = [0 for i in range(n + 1)]}$ |
- Nous simulons les $\purple{\text{b}}$ lâchers de bille par une boucle $\purple{\text{for}}$ :
$\textcolor{#A9A9A9}{\text{5}}\quad\qquad\text{for j in range(b):}$ |
- Nous initialisons la variable $\purple{\text{S}}$, qui donnera le numéro du réservoir qui recueillera la bille.
$\textcolor{#A9A9A9}{\text{6}}\quad\qquad\qquad\text{S = 0}$ |
- Nous simulons le franchissement des $\purple{\text{n}}$ rangées de clous rencontrées par la bille par une nouvelle boucle $\purple{\text{for}}$ :
$\textcolor{#A9A9A9}{\text{7}}\quad\qquad\qquad\text{for k in range (n):}$ |
- Nous nous servons ensuite de la fonction $\purple{\text{randint}}$ pour simuler le choix aléatoire de la gauche ou de la droite.
Si le résultat est $0$, nous considérons que la bille va à gauche. S’il est $1$, nous considérons qu’elle va à droite. Nous comptons ainsi les « succès », en ajoutant ce résultat à la variable $\purple{\text{S}}$ à chaque tour de boucle (soit à chaque clou rencontré).
- Et, nous l’avons dit dans la première partie, le contenu final de $\purple{\text{S}}$ donnera le numéro du réservoir où finit la bille.
$\textcolor{#A9A9A9}{\text{8}}\quad\qquad\qquad\qquad\text{S = S + randint(0, 1)}$ |
- Une fois la bille arrivée dans un réservoir, nous mettons à jour la liste $\purple{\text{R}}$ en indiquant qu’il y a $1$ bille supplémentaire dans le réservoir $\purple{\text{S}}$ :
$\textcolor{#A9A9A9}{\text{9}}\quad\qquad\qquad \text{R[S] = R[S] + 1}$ |
- Ce qui nous intéresse, c’est la fréquence avec laquelle une bille finit dans chacun des réservoirs.
- Nous créons à cet effet une nouvelle liste, que nous nommons $\purple{\text{F}}$, que nous initialisons vide :
$\textcolor{#A9A9A9}{\text{10}}\quad\qquad \text{F = []}$ |
- Cette liste sera de la même longueur que $\purple{\text{R}}$, soit $\purple{\text{n + 1}}$ :
$\textcolor{#A9A9A9}{\text{11}}\quad\qquad \text{for l in range(n + 1):}$ |
- Puisque $\purple{\text{F}}$ contiendra les fréquences, chacun de ses coefficients se calcule en divisant le nombre de billes arrivées dans le réservoir $\purple{\text{l}}$, soit $\purple{\text{R[l]}}$, divisé par le nombre de billes lâchées, soit $\purple{\text{b}}$ :
$\textcolor{#A9A9A9}{\text{12}}\quad\qquad\qquad \text{F.append(R[l] / b)}$ |
- Finalement, nous affichons la répartition des billes après que l’ensemble des lâchers ont été effectués :
$\textcolor{#A9A9A9}{\text{13}}\quad\qquad \text{print(R)}$ |
- Et nous affichons enfin les fréquences correspondantes :
$\textcolor{#A9A9A9}{\text{14}}\quad\qquad \text{print(F)}$ |
- L’algorithme est terminé :
$\begin{aligned} \textcolor{#A9A9A9}{\text{1}}&\quad\text{from random import randint} \\ \textcolor{#A9A9A9}{\text{2}}& \\ \textcolor{#A9A9A9}{\text{3}}&\quad\text{def galton(n,b):} \\ \textcolor{#A9A9A9}{\text{4}}&\quad\qquad\text{R = [0 for i in range(n + 1)]} \\ \textcolor{#A9A9A9}{\text{5}}&\quad\qquad\text{for j in range(b):} \\ \textcolor{#A9A9A9}{\text{6}}&\quad\qquad\qquad\text{S = 0} \\ \textcolor{#A9A9A9}{\text{7}}&\quad\qquad\qquad\text{for k in range (n):} \\ \textcolor{#A9A9A9}{\text{8}}&\quad\qquad\qquad\qquad\text{S = S + randint(0, 1)} \\ \textcolor{#A9A9A9}{\text{9}}&\quad\qquad\qquad\text{R[S] = R[S] + 1} \\ \textcolor{#A9A9A9}{\text{10}}&\quad\qquad\text{F = []} \\ \textcolor{#A9A9A9}{\text{11}}&\quad\qquad\text{for l in range(n + 1):} \\ \textcolor{#A9A9A9}{\text{12}}&\quad\qquad\qquad\text{F.append(R[l] / b)} \\ \textcolor{#A9A9A9}{\text{13}}&\quad\qquad\text{print(R)} \\ \textcolor{#A9A9A9}{\text{14}}&\quad\qquad\text{print(F)} \end{aligned}$ |
Considérons une planche avec $6$ rangées de clous et $7$ réservoirs, et simulons le lâcher de $1\,000$ billes.
Nous entrons : $\purple{\text{galton(6,1000)}}$
- L’algorithme nous retourne, par exemple :
$$\begin{aligned} &\purple{\text{[11, 98, 239, 305, 267, 66, 14]}} \\ &\purple{\text{[0.011, 0.098, 0.239, 0.305, 0.267, 0.066, 0.014]}} \end{aligned}$$
C’est-à-dire qu’il y a donc :
- $11$ billes qui ont fini leur course dans le réservoir $0$, soit une fréquence de $0,011$ ;
- $98$ billes dans le réservoir $1$, soit une fréquence de $0,098$ ;
- $239$ billes dans le réservoir $2$, soit une fréquence de $0,239$ ;
- et cætera.
Conclusion
Conclusion
Appliquez cette fonction Python à l’exemple de la première partie : la planche de Galton modélisée dispose de $4$ rangées de clous.
Simulez un lâcher de $1\,000\,000$ de billes (laissez tourner patiemment l’algorithme, ça peut prendre un peu de temps… mais pas autant que si vous le faisiez manuellement !). Puis comparez les résultats avec la loi de probabilité donnée dans la partie précédente.
- Quelle loi fondamentale des probabilités cela vous évoque-t-il ?