Simulation de lois discrètes

1. Loi générale (tabulée)

Simulons la variable aléatoire discrète X à valeurs dans {1,2,…,8} dont la distribution est fournie par le vecteur suivant:

valeurs_possibles=seq(1,8)
distri_probas=c(0.1,0.2,0.05,0.05,0.05,0.15,0.35,0.05)

On vérifie au passage que la somme des probas fait 1 :

sum(distri_probas)
## [1] 1

1. Inverse de la fonction de répartition

D'abord, on calcule la fonction de répartition, ou CDF (Cumulative Distribution Function), en calculant les sommes partielles des probabilités. Pour cela on écrit une fonction, qui sera réutilisable pour tout vecteur de probas.

repartition=function(p){
  vec_rep=c()
  vec_rep[1]=p[1];
  for(i in 2:length(p))
    vec_rep[i]=vec_rep[i-1]+p[i]
  vec_rep
}

L'algo de simulation peut aussi s'écrire de façon générique par une fonction qui prend en argument le réel aléatoire uniforme sur [0,1] et le vecteur contenant la CDF.

simulation_cdf=function(x,v){
  i=1
  while(x>v[i]){
    i=i+1
  }
    i
}

On aurait aussi pu faire les 2 en même temps (recherche et sommes partielles). Nous verrons cette alternative dans le cas de la loi géométrique, dont le support infini empêche de précalculer la fonction de répartition.

Essayons maintenant notre méthode :

set.seed(42) # au hasard...
simulation_cdf(runif(1),repartition(distri_probas))
## [1] 7

Bon, 1 échantillon, ça ne dit pas grand chose. Pour en faire un grand nombre:

N=100
fr=repartition(distri_probas)
echantillon_cdf=sapply(runif(N),simulation_cdf,fr) # applique la fonction simulation à tous les éléments de runif(N), avec comme second argument le vecteur fr

Combien a-t-on obtenu de 2?

sum(echantillon_cdf==2)
## [1] 17

Pas mal ! Vérifions graphiquement.

hist(echantillon_cdf, breaks=c(0,valeurs_possibles)) # on rajoute 0, sinon le calcul automatique des "boîtes" groupe les valeurs 1 et 2.

plot of chunk unnamed-chunk-8 Si l'on compare à la distribution souhaitée:

barplot(distri_probas)

plot of chunk unnamed-chunk-9

2. Génération par tabulation

On remarque que les probabilités sont toutes multiples de 1/20. On peut donc remplir un tableau de 20 entiers choisis proportionnellement à ces probabilités, et piocher dedans uniformément.

nb_occ=(distri_probas)*20 # nb de répétitions de chaque valeur
tabul=c() #tableau des valeurs 
for(i in 1:8){
  tabul=c(tabul,rep(valeurs_possibles[i],nb_occ[i]))
}
echantillon_tabulation=sample(tabul,replace=TRUE,size=N)# prenons un echantillon de même taille qu'avant
hist(echantillon_tabulation, breaks=c(0,valeurs_possibles))

plot of chunk unnamed-chunk-10

2. Loi binomiale

1. Inverse de la CDF

Rappel: la distribution binomiale \( Binom(n,p) \) vérifie : \( P(X=k)=C_n^k p^k (1-p)^{n-k} \). (On voit déjà venir les erreurs d'arrondi pour certaines valeurs de k…). Deux possibilités: on précalcule toutes les probas cumulées (comme pour l exercice 1) ou on les calcule à la volée.

binom_cdf=function(x,n=N,p=0.5){
  seuil=p^N
  k=0
  while(x>=seuil){
    k=k+1
    seuil=seuil+choose(n,k)*p^(n-k)*(1-p)^k
  }
  k
}
stat_binom=sapply(runif(N*N),binom_cdf)
plot(stat_binom)

plot of chunk unnamed-chunk-11

hist(stat_binom)

plot of chunk unnamed-chunk-11 À comparer avec le générateur fourni par R:

echantillon_rbinom=rbinom(n=N*N,size=N,prob=0.5)
plot(echantillon_rbinom)

plot of chunk unnamed-chunk-12

hist(echantillon_rbinom)

plot of chunk unnamed-chunk-12

En utilisation la loi de Bernoulli

Pour la loi binomiale \( Binom(n,p) \), on peut aussi exploiter le fait que X représente le nombre de succès dans une succession de \( n \) tirages de Bernoulli \( \cal{B}(p) \)

binom_nb=function(n,p){
  sum(runif(n)<p) # compte les coordonnées inférieures à p dans le vecteur de n nombres uniformes runif(n)
}

3. Loi géométrique

1. Inverse de la CDF

Ici le support est infini car la variable géométrique n'est pas bornée. On n'a pas le choix, il faut donc calculer la CDF à la volée.

geom_cdf=function(x,p=0.5){
  seuil=p
  k=1
  while(x>seuil){
    k=k+1
    seuil=seuil+p^k
  }
  k
}
stat_geom=sapply(runif(N*N),geom_cdf)
plot(stat_geom)

plot of chunk unnamed-chunk-14

hist(stat_geom)

plot of chunk unnamed-chunk-14

Avec Bernoulli

Les puissances engendrent beaucoup d'erreurs d'approximation qui peuvent significativement biaiser l'échantillon. On peut obtenir une variable géométrique \( \cal G(p) \) comme le premier succès d'une succession (non bornée) de variables de Bernoulli de même paramètre \( p \).

geom_nb=function(p=0.5){
  k=1
  while(runif(1)>p){
    k=k+1
    }
  k
  }