5.4. Probabilités

5.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

5.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.012783063454406829,
 0.09550257917997018,
 0.3600654282371637,
 0.3962115591173916,
 0.4819515312176119,
 0.6906309160355167,
 0.7507111698091478,
 0.6150890255841224,
 0.4710595008072812,
 0.4162051360125838]

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

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, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 2, 0, 1, 1, 1, 1]

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 [13]: def simul(loi):
   ....:     proba = random()
   ....:     s = loi(0)
   ....:     n = 0
   ....:     while proba >= s:
   ....:         n += 1
   ....:         s += loi(n)
   ....:     return n
   ....: 
In [14]: from math import factorial, exp

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

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

Pour terminer, on peut facilement 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]: [3, 5, 4, 4, 5, 2, 4, 3, 5, 5, 4, 4, 3, 4, 1, 4, 5, 4, 5, 3]

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

Evidemment, Python dispose déjà deux fonctions permettant de calculer aisément la moyenne d’une liste de nombres. On peut par exemple utiliser la fonction sum qui, comme son nom l’indique, calcule la somme des éléments d’une liste (ou plus généralement d’un objet de type itérable).

In [21]: moyenne = lambda liste: sum(liste) / len(liste)

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

Le module numpy dispose même d’une fonction mean (moyenne en anglais).

In [23]: from numpy import mean

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

Bien entendu, le module numpy dipose déjà d’une fonction ad hoc : la fonction var.

In [25]: from numpy import var

In [26]: var([1, 2, 3])
Out[26]: 0.6666666666666666
[3]A nouveau, le module numpy.random dispose déjà de fonctions permettant de simuler la plupart des lois classiques.