• 10 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

Ce cours est en vidéo.

Vous pouvez obtenir un certificat de réussite à l'issue de ce cours.

J'ai tout compris !

Mis à jour le 28/03/2019

Utilisez Numpy pour illustrer le théorème central limite

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Dans le chapitre précédent, nous nous sommes brièvement rappelé les bases de la programmation en Python, et nous nous sommes frottés à la visualisation des données avec Matplotlib. Dans ce chapitre, nous allons commencer à utiliser une autre librairie de la pile scientifique de Python, Numpy.

Numpy contient de nombreuses fonctions et structures de données orientées vers l'algèbre linéaire et l'analyse de données. Vous pouvez imaginer Numpy comme l'équivalent en Python du logiciel Matlab (sans les capacités graphiques, qui sont fournies par Matplotlib).

Pour cette première prise en main, nous allons nous attaquer à un théorème fondamental de la théorie des probabilités, le théorème de la limite centrale.

La distribution Gaussienne

Si à un moment de votre vie, vous vous êtes intéressés aux probabilités, vous avez certainement entendu parler de la distribution Gaussienne, que l'on peut représenter par sa densité :

$\[f(x \; | \; \mu, \sigma^2) = \frac{1}{\sqrt{2\pi\sigma^2} } \; e^{ -\frac{(x-\mu)^2}{2\sigma^2} }\]$

où  $\(\mu\)$ représente la moyenne, et  $\(\sigma\)$ l'écart type de la distribution. Pour une variable aléatoire, la densité a une définition simple.

La probabilité que la variable  $\(x\)$ prenne une valeur entre  $\(a\)$ et  $\(b\)$ est donnée par l'intégrale de la densité de probabilité  de  $\(x\)$ entre  $\(a\)$ et $\(b\)$ . En termes mathématiques :

$\[P(x\in[a,b])=\int_a^bf(x)dx\]$

La forme de cette fonction est ... eh bien pourquoi ne pas utiliser Python pour la dessiner ?

%matplotlib inline  
import numpy as np
import matplotlib.pyplot as plt
from math import sqrt, pi, exp

domaine = range(-100,100)
mu = 0
sigma = 20

# Notez l'utilisation du mot clé lambda. Il est très bien expliqué dans le cours
# "Apprenez à programmer en Python" sur OpenClassrooms.
f = lambda x : 1/(sqrt(2*pi*pow(sigma,2))) * exp(-pow((x-mu),2)/(2*pow(sigma,2)))

y = [f(x) for x in domaine]
plot = plt.plot(domaine, y)
La courbe en cloche
La courbe en cloche

Et voilà la fameuse courbe en cloche. Remarquez qu'elle est centrée en 0 (parce que  $\(\mu=0\)$). Cette fonction est intégrable entre  $\(-\infty\)$ et  $\(\infty\)$. Mais la fonction vaut presque zéro (sans jamais être égale à 0) dès qu'on s'éloigne de son centre. La vitesse à laquelle  $\(f\)$ tend vers 0 en s'éloignant de  $\(\mu\)$ est donnée par $\(\sigma\)$. Essayez de varier les paramètres  $\(\mu\)$  et  $\(\sigma\)$  pour vous rendre compte de leur impact. Par exemple, observez la courbe avec $\(\mu=50\)$, et tentez aussi $\(\sigma=5\)$

Le théorème central limite

Cette distribution est aussi couramment appelée la distribution normale. La raison de cette appellation est une propriété remarquable : beaucoup d'observations dans le monde réel semblent suivre cette loi. Par exemple, si on mesurait la taille de tous les humains sur terre et affichait l'histogramme de nos observations, nous obtiendrions une courbe très proche de celle que vous voyez au-dessus (avec une moyenne et un écart type différents, bien évidemment).

Cette propriété découle d'un théorème fondamental des probabilités, le théorème central limite. Intuitivement, ce théorème déclare que toute somme de variables aléatoires indépendantes et identiquement distribuées tend vers une variable aléatoire gaussienne. Nous allons dans ce chapitre illustrer ce théorème, sans tenter de le démontrer (ce n'est pas chose aisée).

Générez des réalisations de variables aléatoires avec Numpy

Pour commencer, nous allons générer des réalisations de variables aléatoires identiquement distribuées.

Dans ce chapitre, nous allons plutôt utiliser la librairie Numpy, qui rend cette tâche bien plus facile.

vecteur_aleatoire = np.random.rand(30)
plot = plt.scatter(range(30),vecteur_aleatoire)
Réalisation d'une variable aléatoire gaussienne
Réalisation d'une variable aléatoire uniformément distribuée

Voilà. C'est pas bien difficile. Remarquez que ces variables sont uniformément distribuées, c'est-à-dire qu'elles ne semblent pas favoriser une valeur en particulier. Et si au lieu d'un vecteur, nous voulions une matrice?

matrice_aleatoire_a_imprimer = np.random.rand(3,5)
print(matrice_aleatoire_a_imprimer)
matrice_aleatoire_a_grapher = np.random.rand(2,30)
fig = plt.figure()
plot1 = plt.scatter(range(30),matrice_aleatoire_a_grapher[0,:])
plot2 = plt.scatter(range(30),matrice_aleatoire_a_grapher[1,:])
[[ 0.28346313 0.31098521 0.85605644 0.06346737 0.94141766]
 [ 0.85912141 0.03400195 0.41018347 0.88199074 0.41266676]
 [ 0.61338095 0.98663708 0.99128196 0.46062721 0.69029766]]
Une matrice de variable aléatoires uniformément distribuées
Une matrice de variable aléatoires uniformément distribuées

La fonction  rand  prend en argument la taille de la matrice que nous souhaitons générer. Pour accéder à une colonne ou une ligne dans cette matrice, il suffit d'utiliser la syntaxe  [], comme s'il s'agissait d'une liste. Le signe  :  demande à Numpy de nous donner toutes les colonnes, ce qui nous dispense d'écrire explicitement la taille de la matrice. Par exemple, pour une matrice de taille 2x3,  matrice[0:2][0:3]  et  matrice[:,:]  sont équivalents.

Les opérations de base sur les matrices Numpy

Intéressons-nous maintenant à notre problème. Nous voulons simuler un grand nombre de variables aléatoires. Donc nous devons générer, pour chaque variable aléatoire, un grand échantillon (c'est-à-dire un échantillon avec beaucoup d'individus).

En prenant par exemple le cas où ces variables aléatoires sont uniformément distribuées dans l'intervalle [0,1], il nous suffit de générer une matrice avec la fonction  rand.

Considérons ici 100 variables aléatoires. On tire de chacun d'elle 1 échantillon de taille 200 (c'est-à-dire 200 individus). On se retrouve donc avec 100 échantillons de 200 individus chacun.

# Nous allons considérer 100 variables aléatoires, 
# chacune avec 200 échantillons.
matrice_aleatoire = np.random.rand(100,200)

sommes = np.sum(matrice_aleatoire,0)

Le deuxième argument de la fonction  sum  de Numpy dit à la fonction dans quel sens effectuer la somme. S'il vaut 0, la somme sera effectuée le long des lignes, et le résultat sera un vecteur avec autant d'éléments que de colonnes dans la matrice. S'il vaut 1, la somme sera effectuée le long des colonnes, et le résultat sera un vecteur avec autant d'éléments que de lignes dans la matrice. Si l'argument est absent, la fonction renverra simplement un nombre représentant la somme de tous les éléments dans la matrice. Nous pouvons inspecter la taille d'une variable de Numpy grâce à la propriété  shape.

print("La taille de la variable sommes est {}.".format(sommes.shape))
La taille de la variable sommes est (200,).

En pratique, vous passerez certainement beaucoup de temps à vérifier les tailles des tableaux que vous manipulez grâce à leur propriété  shape. La raison en est simple. Pour les opérations d'algèbre linéaire, il y a souvent des contraintes sur la taille des matrices que vous serez amenés à manipuler. Si à un moment vous rencontrez un message d'erreur de la forme :  ValueError: shapes not aligned, pensez à vérifier les tailles de vos matrices.

Visualisation

Ça y est. Dans la variable  sommes  , nous avons un échantillon de taille 200, qui est la réalisation  d'une nouvelle variable aléatoire. Cette nouvelle variable aléatoire est la somme des 100 variables aléatoires identiquement distribuées que nous avions au départ. Si nous plaçons ces points sur un graphique, que va-t-on voir?

plot = plt.scatter(range(200), sommes)
Un échantillon d'une variable aléatoire gaussienne
Un échantillon d'une variable aléatoire gaussienne

Les points semblent se concentrer autour de la valeur 50. Mais il n'est pas évident dans ce graphique de bien comprendre leur comportement. Nous devons certainement changer d'outil de visualisation. Nous voulons voir la fréquence à laquelle chaque valeur est générée par notre variable aléatoire. Le bon outil est un ...

Les histogrammes

Un histogramme est très utile pour étudier une distribution. Et grâce à Matplotlib, nous pouvons en générer un facilement.

plot = plt.hist(sommes)
L'histogramme des sommes
L'histogramme des sommes

Nous commençons à deviner une courbe qui ressemble beaucoup à notre distribution favorite (la distribution gaussienne). Et si nous faisions la même chose avec beaucoup plus que 100 variables, et avec des échantillons beaucoup plus grands que 200 ? Attention, cela risque de prendre quelques secondes de calcul pour votre ordinateur !

matrice_aleatoire = np.random.rand(10000,100000)
sommes = np.sum(matrice_aleatoire,0)
plot = plt.hist(sommes, bins=100)
L'histogramme d'une plus grand échantillon
L'histogramme d'un plus grand échantillon

C'est beaucoup mieux ! Remarquez l'argument  bins  de la fonction  hist. Il dicte à la fonction dans combien de classes répartir les valeurs. C'est essentiel quand nous avons affaire à des données sous forme de nombres réels.

Calculer les propriétés d'un échantillon

Nous aimerions connaître de façon empirique les propriétés de la distribution que nous avons générée. Et heureusement, nous avons Numpy.

print("La moyenne empirique de notre distribution est {}."
      .format(np.mean(sommes)))
print("La moyenne empirique de la variable généré par la fonction rand est {}."
      .format(np.mean(np.random.rand(100000))))
print("La variance empirique de notre distribution est {}."
      .format(np.var(sommes)))
print("La variance empirique de la variable généré par la fonction rand est {}."
      .format(np.var(np.random.rand(100000))))
La moyenne empirique de notre distribution est 5000.20455456666.
La moyenne empirique de la variable généré par la fonction rand est 0.5010223279561243.
La variance empirique de notre distribution est 830.6854133759763.
La variance empirique de la variable généré par la fonction rand est 0.0832842324179482.

La moyenne de notre distribution est égale à la somme des moyennes des distributions qui la composent. La variance est la somme des variances des distributions qui composent notre distribution. Attention, ces propriétés ne sont valables que parce que nos distributions sont indépendantes.

Exemple de certificat de réussite
Exemple de certificat de réussite