Paradoxe des anniversaires

Calcul de la probabilité selon la taille du groupe

L’événement E1=“deux individus au moins ont le même anniversaire” est le complémentaire (le contraire) de l’événement E2=“tous les individus ont des dates différentes”. Calculons la probablité de E2 en fonction du nombre d’individus (plus facile à dénombrer). On néglige les années bissextiles pour simplifier les calculs.

pe2=function(n=20){
  p=1
  for(i in 1:(n-1)){ # remarquer les parenthèses autour de (n-1). 
    p <-p*(365-i)/365
  }
  p
}

On peut maintenant calculer la probabilité qu’au moins 2 individus aient le même anniversaire:

Pcoincidence=function(n){
  1-pe2(n)
}

Pour 30 personnes, cette probabilité est donc de

Pcoincidence(30)
## [1] 0.7063162

Regardons maintenant comme cette probabilité évolue avec n:

x<-1:50
y <- numeric(length(x))
for (i in 1:length(x)) {
  y[i]<-Pcoincidence(i)
}
plot(x,y,xlab="nombre d'individus",ylab="Probabilité de coïncidence d'anniversaires")

Généralisation à un ensemble plus grand

À vous de jouer ! Cette fois, les n individus sont des données (cryptées) et les “dates d’anniversaire” la sortie d’une fonction de hachage à valeurs dans un ensemble A de taille Card(A)=K.

# code à écrire

Simulation

On peut vérifier nos calculs en mesurant cette probabilité à l’aide d’une simulation. On génère un certain nombre (paramétrable) de dates d’anniversaires choisies uniformément entre 1 et 365 (on néglige toujours les années bissextiles) puis on regarde s’il y a au moins 2 valeurs identiques dans le groupe. Ensuite, pour estimer la probabilité, il faut répéter l’expérience…

Écrivons de petites fonctions bien utiles, si possible en dans le “style R”…

gen_pop = function(N = 35) {
  floor(runif(N,min = 0, max = 365))
}

freq_pop = function(N = 35, Ntrials = 100) {
  count = 0 
  for(i in 1:Ntrials) {
    pop = gen_pop(N);
    if(length(pop) != length(unique(pop))) # héhé :)
      count = count + 1
  }
  count / Ntrials
}

Un petit test de nos fonctions:

freq_pop(20)
## [1] 0.43

Regardons maintenant comment la taille de la population influence notre fréquence:

mytab = c()
for(i in 1:40) {
  mytab[i] = freq_pop(i)
}
plot(mytab)

Berk. C’est très variable et avec seulement 100 tirages, ça ne peut pas être bien précis… Essayons avec “un peu” plus de tirages:

mytab = c()
for(i in 1:40) {
  mytab[i] = freq_pop(i,Ntrials = 10000)
}
plot(mytab)

Parfait. C’est cette fois-ci parfaitement conforme à l’évaluation théorique faite dans la première section. C’est un peu long à calculer par contre car il faut beaucoup de simulations pour que ça soit “précis”. Mais que signifie “précis” dans un cas comme celui ci où les valeurs vont changer à chaque nouvelle simulation ? C’est justement une des réponses que vous apprendrez pendant ce cours.

Side note sur l’initialisation des variables

Voici quelques petits essais de code R pour comprendre la sémantique de l’initialisation des tableaux. En R, pas besoin de déclarer une variable. Les tableaux sont indicés à partir de 1 et ils sont dynamiques, c’est à dire qu’il est parfaitement possible d’écrire au delà de la taille actuelle d’un tableau. Par contre, impossible d’écrire dans un tableau non défini… Il faut donc toujours initialiser ses tableaux sous peine de message d’erreur peu compréhensible…

# rm("mytab"");  mytab[12] = 3; print(mytab) ## ne marche pas..
mytab=1:5; mytab[12] = 3; print(mytab) # une initialisation un peu arbitraire du tableau
##  [1]  1  2  3  4  5 NA NA NA NA NA NA  3
mytab=c(); mytab[12] = 3; print(mytab) # une initialisation par un tableau vide
##  [1] NA NA NA NA NA NA NA NA NA NA NA  3
mytab = rep(0,8); mytab[12] = 3; print(mytab) # une initialisation avec des 0
##  [1]  0  0  0  0  0  0  0  0 NA NA NA  3