8.4. Probabilités

8.4.1. Statistiques

Le calcul de la moyenne est on ne peut plus simple : il s’agit de la somme des éléments de la liste divisée par le nombre d’éléments de cette liste [1]. De manière plus formmelle, la moyenne \(m\) d’une liste \((x_1,\dots,x_n)\) de nombres est

\[m=\frac{1}{n}\sum_{k=1}^nx_k\]
In [1]: def moyenne(liste):
   ...:     somme = 0
   ...:     for el in liste:
   ...:         somme += el
   ...:     return somme / len(liste)
   ...: 

In [2]: moyenne([1, 2, 3])
Out[2]: 2.0

On peut donner deux expressions de la variance \(v\) d’une liste \((x_1,\dots,x_n)\) de nombres dont on dispose déjà de la moyenne \(m\).

\[v = \left(\frac{1}{n}\sum_{k=1}^nx_k^2\right)-m^2 = \frac{1}{n}\sum_{k=1}^n(x_k-m)^2\]

En utilisant la première expression, on peut par exemple donner cette fonction de calcul de la variance [2].

In [3]: def variance(liste):
   ...:     s1, s2 = 0, 0
   ...:     n = len(liste)
   ...:     for el in liste:
   ...:         s1 += el
   ...:         s2 += el * el
   ...:     return s2 / n - (s1 / n) ** 2
   ...: 

In [4]: variance([1, 2, 3])
Out[4]: 0.666666666666667

On peut également utiliser une des fonctions de calcul de moyenne définies précédemment.

In [5]: variance = lambda liste: moyenne([el ** 2 for el in liste]) - moyenne(liste) ** 2

In [6]: variance([1, 2, 3])
Out[6]: 0.666666666666667

Si l’on préfère, on peut également utiliser la deuxième expression de la variance.

In [7]: def variance(liste):
   ...:     m = moyenne(liste)
   ...:     return moyenne([(el - m) ** 2 for el in liste])
   ...: 

In [8]: variance([1, 2, 3])
Out[8]: 0.6666666666666666

8.4.2. Simuler une variable aléatoire

Dans la suite, on fera appel à la fonction random du module random qui renvoie un flottant tiré aléatoirement dans l’intervalle \([0,1[\).

In [9]: from random import random

In [10]: [random() for _ in range(10)]
Out[10]: 
[0.5482426686157745,
 0.026431151841090794,
 0.25126388990526305,
 0.30600886835596897,
 0.5612372655336763,
 0.10168486062819282,
 0.4874913243778479,
 0.6872614645961589,
 0.9751794225826002,
 0.6645486996202976]

Cela nous permettra de simuler des variables aléatoires connaissant leurs lois [3].

8.4.2.1. Variables aléatoires finies

On cherche dans un premier temps à simuler une variable aléatoire \(X\) à valeurs dans un ensemble fini, disons \(\{0,\dots,n-1\}\)\(n\in\mathbb{N}^*\), dont on connaît la loi, c’est-à-dire les valeurs de \(\mathbb{P}(X=k)\) pour \(k\in\{0,\dots,n-1\}\).

On construit pour cela une fonction prenant pour argument la loi d’une telle variable aléatoire sous la forme d’une liste de réels positifs de somme 1.

In [11]: def simul(loi):
   ....:     proba = random()
   ....:     s = 0
   ....:     for i, p in enumerate(loi):
   ....:         s += p
   ....:         if proba < s:
   ....:             return i
   ....: 
In [12]: [simul([.3, .5, .2]) for _ in range(20)]
Out[12]: [0, 1, 0, 1, 0, 1, 1, 1, 2, 2, 0, 0, 2, 1, 1, 0, 1, 1, 0, 2]

On pourrait par exemple utiliser la méthode précédente pour simuler une loi binomiale.

In [13]: from scipy.special import binom

In [14]: binomiale = lambda n,p: simul([binom(n, k) * p**k * (1-p)**(n-k) for k in range(n+1)])

In [15]: [binomiale(5, .8) for _ in range(20)]
Out[15]: [3, 5, 3, 5, 5, 5, 4, 3, 4, 4, 4, 3, 4, 3, 4, 4, 5, 4, 4, 5]

In [16]: [binomiale(5, .2) for _ in range(20)]
Out[16]: [0, 0, 2, 2, 2, 2, 1, 0, 0, 0, 3, 1, 1, 2, 1, 2, 0, 0, 1, 1]

Evidemment, il existe un méthode plus simple pour simuler une variable suivant une loi binomiale puisque l’on sait qu’elle est de même loi qu’une somme de variables de Bernoulli indépendantes.

In [17]: def bernoulli(p):
   ....:     return 1 if random() < p else 0
   ....: 

In [18]: def binomiale(n, p):
   ....:     return sum(bernoulli(p) for _ in range(n))
   ....: 

In [19]: [binomiale(5, .8) for _ in range(20)]
Out[19]: [4, 5, 4, 3, 4, 4, 1, 3, 2, 4, 5, 4, 4, 3, 4, 4, 3, 3, 4, 4]

In [20]: [binomiale(5, .2) for _ in range(20)]
Out[20]: [1, 1, 1, 0, 1, 1, 1, 2, 1, 0, 1, 0, 1, 2, 1, 2, 0, 1, 0, 1]

8.4.2.2. Variables aléatoires dénombrables

On désire maintenant simuler une variable aléatoire \(X\) à valeurs dans un ensemble dénombrable, disons \(\mathbb{N}\), dont on connaît la loi, c’est-à-dire les valeurs de \(\mathbb{P}(X=k)\) pour \(k\in\mathbb{N}\).

La loi de cette variable aléatoire ne peut alors plus être représentée sous la forme d’une liste finie ; on la représente donc comme une fonction d’argument un entier \(n\) et renvoyant \(\mathbb{P}(X=n)\).

In [21]: def simul(loi):
   ....:     proba = random()
   ....:     s = loi(0)
   ....:     n = 0
   ....:     while proba >= s:
   ....:         n += 1
   ....:         s += loi(n)
   ....:     return n
   ....: 

On peut utiliser cette méthode pour simuler une loi de Poisson.

In [22]: from math import factorial, exp

# Simulation d'une loi de Poisson
In [23]: poisson = lambda l: simul(lambda n: exp(-l) * l**n / factorial(n))

In [24]: [poisson(2) for _ in range(20)]
Out[24]: [3, 2, 3, 1, 2, 2, 2, 1, 0, 2, 2, 1, 3, 2, 0, 4, 1, 0, 1, 4]

De la même manière, on peut simuler une loi géométrique.

In [25]: from math import factorial, exp

# Simulation d'une loi géométrique
In [26]: geometrique = lambda p: simul(lambda n: 0 if n==0 else (1-p)**(n-1) * p)

In [27]: [geometrique(.2) for _ in range(20)]
Out[27]: [10, 3, 4, 6, 3, 1, 8, 1, 3, 2, 5, 1, 3, 2, 3, 5, 10, 2, 4, 1]

Bien entendu, il est plus facile d’utiliser l’interprétation de la loi géométrique comme le numéro d’un premier succès.

In [28]: def geometrique(p):
   ....:     n = 1
   ....:     while random() > p:
   ....:         n +=1
   ....:     return n
   ....: 

In [29]: [geometrique(.2) for _ in range(20)]
Out[29]: [1, 4, 2, 1, 6, 6, 2, 2, 12, 2, 3, 4, 5, 3, 2, 6, 2, 4, 2, 4]