Bootstrapping
En statistique, on veut souvent rééchantillonner pour tester la précision de nos estimations d’échantillon. On appelle cela le bootstrapping — une méthode fondée sur de multiples tirages aléatoires avec remise. Dans ce labo, nous allons : (1) générer des échantillons aléatoires à partir de fonctions de distribution (avec remise), (2) introduire des boucles et (3) calculer l’écart-type de la distribution de nos échantillons bootstrap.
Dans ce matériel, je m’appuie sur le code mis à disposition par Carsey et Harden (2014 : 217).
Fonctions pertinentes : rnorm(),
rbernoulli(), rbinom(), rpois(),
for()
1. Génération de données
1.1 Distribution normale
La fonction rnorm() permet de générer une suite
aléatoire de nombres à partir d’une distribution normale
hypothétique centrée sur une moyenne de 20 et un écart-type de 4,5. Ici,
nous choisissons de générer 2000 observations.
set.seed(300) # Définition du "seed" pour la reproductibilité
myData <- rnorm(n=2000, mean=20, sd=4.5) # Création d'une distribution normale aléatoire
Pour confirmer que le vecteur myData a été créé
correctement, on vérifie que (1) il y a 2000 observations
(length), (2) la moyenne est approximativement 20
(mean) et (3) l’écart-type est approximativement 4,5
(sd). Note : on ne s’attend pas à obtenir
exactement les valeurs entrées dans rnorm, puisque la
fonction introduit de l’aléatoire.
length(myData) # Combien d’observations ?
## [1] 2000
mean(myData) # Quelle est la moyenne ?
## [1] 20.25773
sd(myData) # Quel est l’écart-type ?
## [1] 4.590852
À titre visuel, voici un graphique du vecteur myData. La ligne rouge pointillée représente la moyenne de cette distribution.
1.2 Autres distributions
Notez que vous pouvez créer une variété de distributions dans R. Voici comment créer celles dont nous avons discuté en classe.
1.2.1 Bernoulli
# Définition du "seed" pour la reproductibilité
set.seed(300)
# Chargement du package purrr
library(purrr)
# Création d'une variable de Bernoulli aléatoire avec n=1 (1 tirage)
# et p=0.5 (probabilité de succès de 50 %)
rbernoulli(n=1, p=0.5)
## Warning: `rbernoulli()` was deprecated in purrr 1.0.0.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## [1] TRUE
Cela renvoie une valeur logique (TRUE ou FALSE) indiquant si vous avez tiré un succès (TRUE) ou non (FALSE).
1.2.2 Binomiale
Imaginez que 50 personnes lancent une pièce équilibrée 10 fois chacune, et qu’on s’intéresse au nombre de piles obtenu par chaque personne. L’ensemble des valeurs possibles est \(\{0,1,2,...,10\}\).
Exercice 1
Si la fonction pour créer des données à partir d’une distribution
binomiale est rbinom(n, size, prob), où n
est le nombre d’observations (personnes), size est le
nombre d’essais (lancers), et prob la probabilité de
succès à chaque essai…
Comment générer une sortie aléatoire pour le nombre de piles obtenu par 50 personnes lançant une pièce équilibrée 10 fois chacune ?
# N'oubliez pas de définir votre "seed" à 123!
set.seed(123)
# Vous devez entrer les bons arguments dans cette fonction :
# rbinom(n=?, size=?, prob=?)
# Réponse
set.seed(123)
rbinom(n=50, size=10, prob=0.5)
## [1] 4 6 5 7 7 2 5 7 5 5 8 5 6 5 3 7 4 2 4 8 7 6 6 9 6 6 5 5 4 3 8 7 6 6 2 5 6 4
## [39] 4 4 3 5 5 4 3 3 4 5 4 7
1.2.3 Poisson
Supposons qu’on veuille créer des données à partir d’une distribution de Poisson qui compte le nombre de courriels reçus par jour. Le nombre attendu de courriels par jour est 30 (i.e. \(\lambda = 30\)).
Je veux simuler le nombre de courriels que je recevrai au cours des 14 prochains jours.
set.seed(300) # Définition du "seed" pour la reproductibilité
rpois(n=14, lambda=30) # Création d'une variable de Poisson aléatoire (n=14, lambda=30)
## [1] 37 34 32 33 29 38 34 32 36 31 42 29 22 36
2. Boucles
Introduisons les boucles avec un exemple très simple. Ici, on veut
afficher 5 observations tirées de myData à l’aide de
sample() et print(). Autrement dit, on tire et
on affiche une observation, cinq fois de suite.
set.seed(300) # Définition du "seed" pour la reproductibilité
for (i in 1:5) # Spécification du nombre d’itérations
{
obs <- sample(myData, size=1) # Tirage d'une observation de myData
print(obs) # Affichage de cette observation
cat("J’ai terminé", i, "itérations \n") # Message après chaque itération
}
## [1] 13.85058
## J’ai terminé 1 itérations
## [1] 18.4574
## J’ai terminé 2 itérations
## [1] 18.57355
## J’ai terminé 3 itérations
## [1] 22.5185
## J’ai terminé 4 itérations
## [1] 22.79222
## J’ai terminé 5 itérations
On peut utiliser des boucles pour automatiser un grand nombre de choses. Dans les prochaines sous-sections, nous les utiliserons pour illustrer deux principes importants : la loi des grands nombres et le théorème central limite.
2.1 Loi des grands nombres
Créons une fonction die_mean() pour calculer la moyenne
de n lancers de dé.
die <- 1:6 # Création d'un vecteur "die" avec tous les nombres de 1 à 6
die_mean <- function(n) {
# Échantillonnage avec remise "n" fois dans le vecteur die
mean(sample(die, size=n, replace=TRUE))
}
Calcul de la moyenne de n lancers de dé avec
die_mean().
set.seed(500) # Définition du "seed" pour la reproductibilité
for (n in c(10,100,1000,10000,100000))
{
result <- die_mean(n)
cat("La moyenne de", n, "lancers de dé est", result, "\n")
}
## La moyenne de 10 lancers de dé est 3.2
## La moyenne de 100 lancers de dé est 3.44
## La moyenne de 1000 lancers de dé est 3.492
## La moyenne de 10000 lancers de dé est 3.4994
## La moyenne de 1e+05 lancers de dé est 3.50887
La moyenne d’échantillon se rapproche de la valeur attendue (paramètre de population) à mesure que la taille de l’échantillon augmente. C’est la loi des grands nombres.
2.2 Théorème central limite
Tirer i observations à partir d’un vecteur de
moyennes de 15 lancers de dé avec
replicate() et tracer les résultats avec
hist().
set.seed(100) # Définition du "seed" pour la reproductibilité
for (i in c(100,1000,100000))
{
x <- replicate(i, {
mm <- die_mean(15) # Moyenne de 15 lancers
mean(mm)
})
a <- round(sd(x), digits=3)
hist(x,
xlab="Moyenne de 15 lancers de dé",
xlim=c(1,6),
col="#4286f4",
main=paste("Histogramme pour ", i, " tirages aléatoires (sd = ", a, ")", sep=""))
}
Vous pouvez cliquer sur ces graphiques pour les examiner de plus près !
La distribution de la moyenne d’échantillon tend vers une distribution normale lorsque la taille de l’échantillon augmente. C’est le théorème central limite.
3. Bootstrapping
Le bootstrapping est une façon de tenir compte de l’incertitude lorsque nous mesurons des estimations d’échantillon. En utilisant des tirages aléatoires avec remise, on calcule nos estimations sur de nombreux échantillons aléatoires tirés de notre distribution d’origine.
Ici, nous calculons la moyenne de 1000 échantillons tirés d’une distribution normale aléatoire. La moyenne de chacun de ces échantillons est stockée dans un vecteur (bootstrap.results). Ce qui nous intéresse, c’est l’incertitude de l’estimation (ici : la moyenne), mesurée par l’écart-type de la distribution des moyennes.
set.seed(200) # Définition du "seed" pour la reproductibilité
n.samples <- 1000 # Nombre d’échantillons bootstrap
bootstrap.results <- c() # Création d'un vecteur vide pour stocker les résultats
for (i in 1:n.samples)
{
bootstrap.results[i] <- mean(rnorm(2000, 20, 4.5)) # Moyenne de l’échantillon bootstrap
}
length(bootstrap.results) # Vérification : 1000 moyennes
## [1] 1000
summary(bootstrap.results) # Vérification
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 19.64 19.93 20.00 20.00 20.07 20.32
sd(bootstrap.results) # Écart-type de la distribution des moyennes
## [1] 0.1041927
par(mfrow=c(2,1), pin=c(5.8,0.98)) # Combinaison de graphiques
hist(bootstrap.results,
col="#d83737",
xlab="Moyenne",
main=paste("Moyennes de 1000 échantillons bootstrap (DGP)"))
hist(myData,
col="#37aad8",
xlab="Valeur",
main=paste("Distribution de myData"))
Exercice 2
Fixez votre “seed” à 120. Calculez 50 moyennes (i.e. pour 50
échantillons différents) à partir de la distribution suivante : une
variable de Poisson aléatoire comprenant 200 observations avec un lambda
de 7. Stockez vos résultats (ces 50 moyennes) dans un vecteur appelé
bootstrap.results. Quel est le résumé de ce vecteur avec
summary() ?
# N'oubliez pas de définir votre "seed" à 120!
set.seed(120)
# Écrivez votre code ici
# Réponse
set.seed(120) # Définition du "seed" pour la reproductibilité
n.samples <- 50 # Nombre d’échantillons bootstrap
bootstrap.results <- c() # Création d'un vecteur vide pour stocker les résultats
for (i in 1:n.samples)
{
bootstrap.results[i] <- mean(rpois(n=200, lambda=7)) # Moyenne de l’échantillon bootstrap
}
summary(bootstrap.results) # Résultat
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 6.610 6.860 6.987 6.999 7.120 7.455