Chapitre 6 : Génération aléatoire

Dimension: px
Commencer à balayer dès la page:

Download "Chapitre 6 : Génération aléatoire"

Transcription

1 Chapitre 6 : Génération aléatoire Alexandre Blondin Massé Laboratoire d informatique formelle Université du Québec à Chicoutimi 12 février 2013 Cours 8STT105 Département d informatique et mathématique A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

2 Table des matières 1 Simulation de variables aléatoires 2 Le module random de Python 3 Applications 4 Exercices A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

3 Mise en contexte Tous les langages de programmation fournissent un générateur aléatoire de variable uniforme sur [0,1] ; Considérez une variable aléatoire X dont la fonction de masse est p(1) = 1/2, p(2) = 1/6 et p(3) = 1/3. Comment peut-on simuler X à partir d une uniforme sur [0, 1]? L idée est de partitionner l intervalle [0, 1]. On génère une valeur u entre 0 et 1 et 1 si 0 u < 1/2, alors on retourne 1 ; 2 si 1/2 u < 2/3, alors on retourne 2 et 3 si 2/3 u < 1, alors on retourne 3. A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

4 Exemple Implémentation : import random def va(): u = random.random() if 0 <= u < 1./2: return 1 elif 1./2 <= u < 2./3: return 2 else: return 3 Utilisation : >>> import va >>> valeurs = [va.va() for _ in range(1000)] >>> [valeurs.count(i)/ for i in [1,2,3]] [0.514, 0.163, 0.323] A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

5 La méthode de comparaison Théorème Soit X une variable aléatoire discrète qui peut prendre les valeurs x 0, x 1,... et dont la fonction de masse p pour ces valeurs est décrite par p 0, p 1,.... Soit U une variable aléatoire uniforme sur l intervalle 0. Alors P (X = x 0 ) = P (0 U < p 0 ); (1) P (X = x i ) = i 1 i P p j U <. (2) j=0 j=0 p j A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

6 Loi binomiale import random def combinaison(n, k): if n == 0: return 0 elif k == 0 or k == n: return 1 else: return combinaison(n - 1, k - 1) + combinaison(n - 1, k) def binomiale(n, p): r""" Simulation d une variable aleatoire binomiale de parametres (n, p) """ u = random.random() i = -1 c = 0 while u >= c: i += 1 c += combinaison(n, i) * p**i * (1 - p)**(n - i) return i A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

7 Loi de Poisson Question Utilisez la méthode de comparaison pour simuler une variable de Poisson en Python. Rappel : la fonction de masse d une variable de Poisson de paramètre λ est p(x = i) = e λ λ i, pour i = 0, 1, 2,... i! A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

8 Solution Solution import random import math def factorielle(n): if n == 0: return 1 elif n > 0: return n * factorielle(n - 1) def poisson(lambd): u = random.random() i = 0 c = math.exp(-lambd) while u >= c: i += 1 c += math.exp(-lambd) * lambd**i / factorielle(i) return i A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

9 Variables aléatoires continues Jusqu à maintenant, nous nous sommes concentrés sur les variables aléatoires discrètes avec la méthode de comparaison On peut grâce à cette méthode simuler n importe quelle variable aléatoire discrète. Qu en est-il du cas continu? Comment simuler une loi uniforme sur l intervalle [α, β]? Comment simuler une loi exponentielle? Comment simuler une loi normale? A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

10 Lois uniformes Supposons que nous disposons d un générateur de loi uniforme sur l intervalle [0, 1]. Comment générer une loi uniforme sur l intervalle [α, β]? Il suffit d utiliser le fait que si U Uniforme(0, 1), alors U (β α) + α Uniforme(α, β). A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

11 Théorème de la transformation inverse Théorème Soit X une variable aléatoire continue et F (x) sa fonction de répartition. Si F (x) est continue et strictement croissante, alors U = F (X) est une variable aléatoire dont la distribution est uniforme sur [0, 1]. Réciproquement, si U est une variable aléatoire uniforme sur [0, 1], alors la variable F 1 (U) est une variable aléatoire dont F est la fonction de répartition. A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

12 Loi exponentielle Soit X une variable aléatoire qui suit une loi exponentielle de paramètre λ ; Alors la fonction de répartition de X est : F (x) = 1 e λx, pour x 0. Inversons F : F (x) = 1 e λx y = 1 e λx y 1 = e λx 1 y = e λx ln(1 y) = λx ln(1 y) x =. λ A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

13 Implémentation import random import math def exponentielle(lambd): u = random.random() return math.log(1 - u) / -lambd Résultat : >>> import exponentielle >>> exponentielle.exponentielle(10) >>> exponentielle.exponentielle(10) >>> >>> sum(exponentielle.exponentielle(10) for _ in range(1000)) >>> _/ A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

14 Loi normale Théorème (Théorème central limite) Soient X 1, X 2,..., X n des variables aléatoires suivant une même loi de probabilité de moyenne µ et de variance σ 2. Soit X = n i=1 X i. Alors lim X N (nµ, n nσ2 ). Rappelons que si U Uniforme(0, 1), alors E[U] = 1/2 et Var(U) = 1/12. Par conséquent, si on prend une somme de n = 12 variable uniformes, on obtient que 12 ( Z = U i 1 ) 2 i=1 est une bonne approximation d une loi normale d espérance 0 et de variance 1. A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

15 Théorème de Box et Muller Théorème (Box et Muller, 1958) Soient U 1 et U 2 deux variables aléatoires uniformes et indépendantes sur l intervalle [0, 1]. Alors les variables Z 1 = 2 ln(u 1 ) cos(2πu 2 ) Z 2 = 2 ln(u 1 ) sin(2πu 2 ) sont toutes deux indépendantes et suivent une loi normale centrée réduite, c est-à-dire de moyenne 0 et de variance 1. A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

16 Implémentation Question Utilisez le théorème de Box et Muller pour simuler une variable aléatoire normale de paramètres (µ, σ 2 ). Solution import random import math def normale(mu, sigma): u1 = random.random() u2 = random.random() return math.sqrt(-2 * math.log(u1)) * math.cos(2 * math.pi * u2) A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

17 Solution Solution def test_normale(mu, sigma): histogramme = {} nb_tests = for _ in range(nb_tests): v = round(normale(mu, sigma), 4) if v not in histogramme: histogramme[v] = 1 else: histogramme[v] += 1 fichier = open( test-normale.dat, w ) for (k,v) in histogramme.iteritems(): fichier.write( %s,%s\n % (k,v * 1.0 / nb_tests)) A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

18 Génération aléatoire en Python Le module random offre les fonctions de base pour manipuler des nombres aléatoires en Python ; La documentation se trouve à ; Le module numpy offre plusieurs services supplémentaires pour la génération aléatoire reference/routines.random.html ; Le module matplotlib permet d afficher rapidement des histogrammes et des graphiques A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

19 Variables uniformes Il y a plusieurs types de variables uniformes : random.random() retourne un nombre aléatoire sur l intervalle [0, 1) ; random.randint(a, b) retourne un nombre aléatoire entier sur l intervalle [a, b] ; random.uniform(a, b) retourne un nombre aléatoire réel sur l intervalle [a, b) ; A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

20 Fonctions sur les listes Comme la liste est un type de base en Python, certaines fonctions aléatoires sont très pratiques ; choice(l) retourne un élément au hasard dans la liste L ; sample(l, k) retourne un échantillon aléatoire de k éléments choisis dans la liste sans répétition ; shuffle(l) mélange les éléments de la liste. Cette fonction modifie la liste L. A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

21 Jeu de cartes (1/2) La fonction shuffle du module random permet de représenter facilement un jeu de cartes : Exemple import random couleurs = [ pique, trefle, carreau, coeur ] valeurs = [ as, 2, 3, 4, 5, 6, 7, 8, 9, 10, valet, dame, roi ] paquet = [ (v,c) for v in valeurs for c in couleurs ] # Une carte au hasard print Une carte ; print print random.choice(paquet) print # On prend 6 mains de 5 cartes print Repetitions possibles ; print for _ in range(6): print random.sample(paquet, 5) print # On melange les cartes random.shuffle(paquet) # On prend 6 mains de 5 cartes print Sans repetition ; print for i in range(6): print paquet[5*i:5*i+5] A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

22 Jeu de cartes (2/2) Résultat Une carte ( roi, coeur ) Repetitions possibles [( roi, pique ), (3, pique ), ( as, carreau ), ( as, coeur ), (5, coeur )] [(8, pique ), (7, carreau ), (4, trefle ), (10, coeur ), (9, trefle )] [(3, carreau ), (3, pique ), ( valet, coeur ), (3, trefle ), (4, carreau )] [( roi, carreau ), (7, carreau ), (9, carreau ), ( as, coeur ), ( dame, trefle )] [( valet, pique ), (8, trefle ), (6, carreau ), (5, trefle ), (10, coeur )] [( valet, carreau ), ( dame, trefle ), (3, trefle ), ( roi, pique ), (9, trefle )] Sans repetition [(2, pique ), (10, carreau ), ( as, pique ), (5, pique ), (6, carreau )] [(3, pique ), (3, trefle ), (7, pique ), ( roi, pique ), ( dame, carreau )] [(2, carreau ), ( as, coeur ), (6, pique ), (7, carreau ), ( valet, pique )] [(6, trefle ), (5, trefle ), (8, carreau ), (9, trefle ), (4, trefle )] [(4, carreau ), (5, carreau ), (6, coeur ), (10, coeur ), ( dame, coeur )] [(9, pique ), ( valet, carreau ), (2, coeur ), (9, carreau ), ( as, trefle )] A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

23 Lois de probabilité expovariate(lambd) simule une loi exponentielle de paramètre λ ; normalvariate(mu, sigma) simule une loi normale de moyenne µ et d écart-type σ. La fonction gauss(mu, sigma) fait la même chose, mais un peu plus efficacement. Les autres lois de probabilité habituelles sont fournies par numpy : Poisson ; Binomiale ; Hypergéométrique ; Zipf ; Chi-carrée ; etc. A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

24 Numpy Par exemple, pour simuler une loi de Poisson, il suffit d entrer les commandes suivantes : >>> import numpy as np >>> s = np.random.poisson(5, 10000) >>> import matplotlib.pyplot as plt >>> count, bins, ignored = plt.hist(s, 14, normed=true) >>> plt.show() A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

25 Contrôler l état du générateur aléatoire La fonction seed(v) initialise le générateur à la valeur v. Ceci permet d obtenir les mêmes valeurs lorsqu on fait rouler le programme plusieurs fois ou sur des machines différentes. s = getstate() sauvegarde l état du système dans la variable s. setstate(s) restore l état du système selon s. jumpahead(n) change l état interne du générateur. Surtout utilisé lorsqu on parallélise et qu on souhaite que les différents forks aient des valeurs différentes. A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

26 Méthode de Monte-Carlo Méthode ayant pour objectif d estimer une valeur numérique à l aide de procédés aléatoires ; À la base de la plupart des algorithmes probabilistes ; La version classique doit en général être modifiée pour que l algorithme soit plus performant, c est-à-dire qu il converge plus rapidement ; Lorsqu on dispose d un générateur aléatoire, on peut estimer par exemple l aire d une surface complexe ; A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

27 Estimation du nombre π >>> import random >>> points = [(random.random(), random.random()) for _ in range(1000)] >>> disque = filter(lambda (x,y): x**2 + y**2 <= 1, points) >>> 4*len(disque)*1.0 / >>> >>> points = [(random.random(), random.random()) for _ in range(100000)] >>> disque = filter(lambda (x,y): x**2 + y**2 <= 1, points) >>> 4*len(disque)*1.0 / On génère n points aléatoires de coordonnées (x, y), avec 0 x, y < 1 ; Soit D le nombre de points à l intérieur du quart de disque ; La probabilité qu un point se trouve sur le quart de disque est π/4 ; Ainsi, π 4D/n. A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

28 Fractales aléatoires def montagne(h): # Initialement, on a un triangle points = [ (-1.0,0.0), (0.0,1.0), (1.0,0.0) ] for i in range(15): nouveaux_points = [] for j in range(len(points) - 1): (a,b) = points[j] (c,d) = points[j+1] # On calcule le point milieu de chaque segment # puis on perturbe la coordonnee y avec un facteur # h**(-i) * random() (m,n) = (0.5 * (a + c), 0.5 * (b + d) + h**(-i) * random()) nouveaux_points.append((a,b)) nouveaux_points.append((m,n)) nouveaux_points.append(points[-1]) points = nouveaux_points return points A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

29 Montagnes h = 1.5 h = 1.8 h = 2 h = 3 h = 5 h = 10 A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

30 Génération d arbres import turtle import random def arbre(x=0, y=-200, **kwds): turtle.speed(0) turtle.penup() turtle.goto(x, y) turtle.setheading(90) turtle.pendown() arbre_rec(**kwds) def arbre_rec(hauteur=10, level=0): turtle.forward(hauteur) (x, y, h) = (turtle.xcor(), turtle.ycor(), turtle.heading()) if level > 0: turtle.left(30) arbre_rec(0.7 * hauteur, level - 1) turtle.penup(); turtle.goto(x, y); turtle.setheading(h); turtle.pendown() turtle.right(30) arbre_rec(0.7 * hauteur, level - 1) A. Blondin Massé (UQAC) Chapitre 6 12 février / 35

31 Exercices (1) Écrivez une fonction Python qui simule un dé pipé de six faces qui tombe 2 fois plus souvent sur un nombre pair que sur un nombre impair. (2) Utilisez le théorème d inversion pour simuler une variable aléatoire uniforme sur l intervalle [α, β]. (3) Implémentez la fonction shuffle en n utilisant que la fonction randint. (4) Au Poker, quelle est la probabilité d obtenir un carré? Écrivez un petit programme Python qui suggère que la probabilité que vous avez calculée est correcte. (5) Même question avec une main pleine. A. Blondin Massé (UQAC) Chapitre 6 12 février / 35