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
cette page qui documente l’ancienne syntaxe qui est encore très présente dans les codes que l’on trouve dans les livres ou sur le web.
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])