Illustration en numpy

1.2. Illustration en numpy#

Dans le module numpy il y a un sous-module random qui permet la création de nombres pseudo-aléatoires et leur transformation pour simuler les lois de probabilités usuelles (discrètes et continues).

Dans ce cours, on utilise une version de numpy postérieure à la version 1.16 et nous allons donc utiliser la syntaxe moderne qui repose sur un objet de type Generator. On recommande vivement la lecture de

Pour créer un objet Generator on utilise la fonction default_rng du module numpy.random. Cette fonction renvoie un objet qui correspond à un générateur de nombres pseudo-aléatoires utilisant l’algorithme PCG64. Voici par exemple un appel possible.

import numpy as np
from numpy.random import default_rng, SeedSequence

sq = SeedSequence()
rng = default_rng(sq)
sq
SeedSequence(
    entropy=338196897504820867970673815411622234078,
)
rng
Generator(PCG64) at 0x110123300

Dans l’appel précédent l’objet rng est créé à partir d’un objet sq obtenu via l’appel de SeedSequence. Cet objet représente l’état initial du générateur, la graine. Le fait de stocker cet état dans une variable sq permet de répliquer des résultats.

Maintenant que l’objet rng est initialisé, on peut l’utiliser. La liste des méthodes existantes pour l’objet rng s’obtient en utilisant la fonction python dir. Dans l’appel suivant on obtient les noms des lois usuelles simulables via l’appel de ces méthodes.

print(dir(rng))
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '_bit_generator', '_poisson_lam_max', 'beta', 'binomial', 'bit_generator', 'bytes', 'chisquare', 'choice', 'dirichlet', 'exponential', 'f', 'gamma', 'geometric', 'gumbel', 'hypergeometric', 'integers', 'laplace', 'logistic', 'lognormal', 'logseries', 'multinomial', 'multivariate_hypergeometric', 'multivariate_normal', 'negative_binomial', 'noncentral_chisquare', 'noncentral_f', 'normal', 'pareto', 'permutation', 'permuted', 'poisson', 'power', 'random', 'rayleigh', 'shuffle', 'spawn', 'standard_cauchy', 'standard_exponential', 'standard_gamma', 'standard_normal', 'standard_t', 'triangular', 'uniform', 'vonmises', 'wald', 'weibull', 'zipf']

Par exemple pour obtenir 10 réalisations de la loi uniforme discrète sur \(\{0,\dots,100\}\) on utilise la méthode integers de l’objet rng via l’appel:

rng.integers(low=0, high=100, size=10)
array([ 1, 49, 82, 96,  3, 70, 89, 10, 95, 55])

Un deuxième appel consécutif donne des réalisations différentes (et supposées indépendantes par car les nombres pseudo-aléatoires vérifient de bonnes propriétés d’indépendance…). Par exemple:

rng.integers(low=0, high=100, size=10)
array([51, 89, 74, 55, 23, 50, 47, 13, 16, 50])

Comme on a stocké la graine du générateur dans la variable sq il est possible de reproduire les mêmes nombres aléatoires en créant un nouvel objet Generator(PCG64) initialisé via sq. Le même algorithme déterministe et la même graine donne les mêmes nombres pseudo-aléatoires.

rng_copy = default_rng(sq)
rng_copy.integers(low=0, high=100, size=20)
array([ 1, 49, 82, 96,  3, 70, 89, 10, 95, 55, 51, 89, 74, 55, 23, 50, 47,
       13, 16, 50])