library(tidyverse)TP Statistiques Bayésiennes: modèles hierarchiques et MCMC
Objectifs
Ce TP a pour objectifs :
- Rappeler les équations analytiques du modèle Normal — Normal — Inverse-Gamma conjugué (moyenne inconnue et variance inconnue).
- Implémenter en R les formules analytiques des postérieurs (pour la moyenne et la variance) et visualiser ces distributions.
- Mettre en place un échantillonneur de Gibbs pour le même modèle et illustrer le fonctionnement des algorithmes MCMC.
- Comparer empiriquement les distributions analytiques et les distributions empiriques obtenues.
Modèle et rappels
Nous considérons les observations \(y_1, \dots, y_n\) modélisées par :
\[ y_i \mid \mu, \sigma^2 \overset{\text{iid}}{\sim} \mathcal{N}(\mu, \sigma^2), \]
et la hiérarchie de priors conjuguées suivante : \[ \mu \mid \sigma^2 \sim \mathcal{N}(\mu_0, \sigma^2 / \kappa_0),\qquad \sigma^2 \sim \text{Inv-Gamma}(\alpha_0, \beta_0), \]
où la paramétrisation de l’inverse-gamma est :
\[p(\sigma^2) \propto (\sigma^2)^{-\alpha_0-1} \exp\left(-\dfrac{\beta_0}{\sigma^2}\right).\]
Formules analytiques du postérieur
Avec les notations :
- \(n\) = nombre d’observations,
- \(\bar{y} = n^{-1} \sum_i y_i\),
- \(S = \sum_i (y_i - \bar{y})^2\),
les paramètres postérieurs conjugués sont :
\[ \kappa_n = \kappa_0 + n, \qquad \mu_n = \frac{\kappa_0 \mu_0 + n \bar{y}}{\kappa_0 + n}. \]
Pour la variance (paramètres de l’Inverse-Gamma a posteriori) :
\[ \alpha_n = \alpha_0 + \frac{n}{2}, \qquad \beta_n = \beta_0 + \frac{1}{2} S + \frac{\kappa_0 n}{2(\kappa_0 + n)} (\bar{y} - \mu_0)^2. \]
Les distributions a posteriori conjuguées sont alors :
- \(\sigma^2 \mid y \sim \text{Inv-Gamma}(\alpha_n, \beta_n)\),
- \(\mu \mid \sigma^2, y \sim \mathcal{N}(\mu_n, \sigma^2 / \kappa_n)\),
- Marginalement, \(\mu \mid y\) suit une Student-\(t\).
TP (format question / indice / réponse)
Exercice 1 — Simulation de données et calcul analytique des postérieurs
Simulez un jeu de données \(n=30\) avec \(\mu_{true}=1.5\) et \(\sigma^2_{true}=2.0\). Choisissez les hyperparamètres \(\mu_0=0,\ \kappa_0=1,\ \alpha_0=2,\ \beta_0=1\) et calculez \(\bar{y}, S\) et les paramètres postérieurs \(\kappa_n,\mu_n,\alpha_n,\beta_n\). Affichez ces valeurs.
Calculez d’abord la moyenne empirique \(\bar{y}\) et \(S=\sum (y_i-\bar{y})^2\). Ensuite appliquez les formules du rappel.
set.seed(2025)
n <- 30
mu_true <- 1.5
sigma2_true <- 2.0
y <- rnorm(n, mean = mu_true, sd = sqrt(sigma2_true))
# hyperparameters
mu0 <- 0
kappa0 <- 1
alpha0 <- 2
beta0 <- 1
# statistics
ybar <- mean(y)
S <- sum((y - ybar)^2)
# posteriors
kappa_n <- kappa0 + n
mu_n <- (kappa0 * mu0 + n * ybar) / kappa_n
alpha_n <- alpha0 + n/2
beta_n <- beta0 + 0.5 * S + (kappa0 * n) / (2 * kappa_n) * (ybar - mu0)^2
list(ybar = round(ybar,4), S = round(S,4), kappa_n = kappa_n, mu_n = round(mu_n,4),
alpha_n = alpha_n, beta_n = round(beta_n,4))$ybar
[1] 1.7924
$S
[1] 55.2818
$kappa_n
[1] 31
$mu_n
[1] 1.7346
$alpha_n
[1] 17
$beta_n
[1] 30.1955
Exercice 2 — Visualisation des postérieurs analytiques
Tracez les graphiques suivants :
- la densité a posteriori de \(\sigma^2\) (Inv-Gamma avec \(\alpha_n,\beta_n\)),
- la densité conditionnelle \(\mu\mid\sigma^2\) pour une valeur représentative de \(\sigma^2\) (par ex. la moyenne postérieure)
Utilisez la densité de l’Inverse-Gamma et simulez \((\sigma^2,\mu)\) en tirant \(\sigma^2\sim\text{Inv-Gamma}(\alpha_n,\beta_n)\) puis \(\mu\mid\sigma^2\sim\mathcal{N}(\mu_n,\sigma^2/\kappa_n)\).
# grid for sigma2
sigma2_grid <- seq(0.01, 6, length.out = 400)
# Inverse-Gamma density function
inv_gamma_density <- function(x, shape, scale) {
beta <- scale
alpha <- shape
(beta^alpha) / gamma(alpha) * x^(-alpha - 1) * exp(-beta / x)
}
# posterior density of sigma2
p_sigma2 <- data.frame(sigma2 = sigma2_grid,
density = inv_gamma_density(sigma2_grid, alpha_n, beta_n))
# conditional mu | sigma2 at sigma2 = posterior mean of sigma2 (approx: beta_n/(alpha_n-1))
sigma2_rep <- beta_n / (alpha_n - 1)
mu_sd_cond <- sqrt(sigma2_rep / kappa_n)
p_mu_cond <- data.frame(mu = seq(mu_n - 3*mu_sd_cond, mu_n + 3*mu_sd_cond, length.out = 300))
p_mu_cond$density <- dnorm(p_mu_cond$mu, mean = mu_n, sd = mu_sd_cond)
# plots
p1 <- ggplot(p_sigma2, aes(x=sigma2, y=density)) + geom_line(color='darkred') +
labs(title='Posterior of sigma^2 (Inv-Gamma)', x=expression(sigma^2), y='densite') + theme_minimal()
p2 <- ggplot(p_mu_cond, aes(x=mu, y=density)) + geom_line(color='darkblue') +
labs(title=expression('Conditional posterior ' ~ mu ~ '| ' ~ sigma^2), x=expression(mu), y='densite') + theme_minimal()
p1
p2
Implémentation d’un Gibbs « à la main »
Aide pour l’implémentation d’un échantillonneur de Gibbs
Pour implémenter un échantillonneur de Gibbs, il faut connaître les distributions conditionnelles suivantes:
- \(p(\sigma^2 \mid \mu, y)\) (paramètres de l’Inverse-Gamma a posteriori) ;
- \(p(\mu \mid \sigma^2, y)\) (moyenne et variance conditionnelles).
On rappelle que ces distributions sont :
- \(p(\sigma^2 \mid \mu, y) \sim \text{Inv-Gamma}\big(\alpha_0 + n/2,\; \beta_0 + \tfrac{1}{2}\sum_i (y_i-\mu)^2\big)\).
- \(p(\mu \mid \sigma^2, y) \sim \mathcal{N}\big(\mu_n,\; \sigma^2 / \kappa_n\big)\), avec \(\kappa_n = \kappa_0 + n\) et \(\mu_n = (\kappa_0\mu_0 + n\bar y)/(\kappa_0 + n)\).
Ces formules serviront directement pour tirer les mises à jour dans un Gibbs exact.
Exercice 3 — Implémenter une mise à jour
Implémentez en R une fonction qui effectue une mise à jour unique (un pas de Gibbs) :
Utilisez rgamma() / 1/rgamma() pour tirer l’Inverse-Gamma, et rnorm() pour tirer la normale conditionnelle.
# inputs: mu_curr, sigma2_curr, y, hyperparametres
# outputs: mu_new, sigma2_new
gibbs_step <- function(mu_curr, sigma2_curr, y, mu0, kappa0, alpha0, beta0) {
n <- length(y)
# sigma2 | mu, y ~ Inv-Gamma(alpha_post, beta_post)
alpha_post <- alpha0 + n/2
S_mu <- sum((y - mu_curr)^2)
beta_post <- beta0 + 0.5 * S_mu
sigma2_new <- 1 / rgamma(1, shape = alpha_post, rate = beta_post)
# mu | sigma2, y ~ Normal(mu_n, sigma2 / kappa_n)
kappa_n <- kappa0 + n
mu_n <- (kappa0 * mu0 + n * mean(y)) / kappa_n
sd_mu <- sqrt(sigma2_new / kappa_n)
mu_new <- rnorm(1, mean = mu_n, sd = sd_mu)
return(list(mu = mu_new, sigma2 = sigma2_new))
}
# quick test
set.seed(1)
res_test <- gibbs_step(mu_curr = mean(y), sigma2_curr = var(y), y = y,
mu0 = mu0, kappa0 = kappa0, alpha0 = alpha0, beta0 = beta0)
res_test$mu
[1] 2.075588
$sigma2
[1] 2.037998
Exercice 4 — Implémenter la boucle Gibbs complète
À partir de la fonction précédente, codez la boucle Gibbs complète qui produit niter itérations, applique un burn-in et retourne des échantillons conservés pour mu et sigma2. Affichez des diagnostics (traceplots, densités) et comparez sommairement aux valeurs analytiques (moyennes postérieures).
Stockez les chaînes dans des vecteurs numériques et utilisez plot() / ggplot2 pour les diagnostics. Pensez à fixer la graine pour reproductibilité.
set.seed(42)
niter <- 6000
nburn <- 1000
mu_chain <- numeric(niter)
sigma2_chain <- numeric(niter)
# initialisation
for(t in 2:niter) {
step <- gibbs_step(mu_chain[t-1], sigma2_chain[t-1], y, mu0, kappa0, alpha0, beta0)
mu_chain[t] <- step$mu
mu_chain[1] <- mean(y)
sigma2_chain[1] <- var(y)
sigma2_chain[t] <- step$sigma2
}
# extract post-burn-in
mu_samps_gibbs <- mu_chain[(nburn+1):niter]
sigma2_samps_gibbs <- sigma2_chain[(nburn+1):niter]
# diagnostics
plot(mu_samps_gibbs, type='l', main='Traceplot mu (Gibbs)', ylab='mu')
plot(sigma2_samps_gibbs, type='l', main='Traceplot sigma2 (Gibbs)', ylab='sigma2')
dens_mu = tibble(x = density(mu_samps_gibbs)$x, y = density(mu_samps_gibbs)$y)
dens_sigma = tibble(x = density(sigma2_samps_gibbs)$x, y = density(sigma2_samps_gibbs)$y)
# comparison with analytical posteriors
p1 + geom_line(data = dens_sigma, aes(x=x, y=y), color='red', linetype='dashed')
p2 + geom_line(data = dens_mu, aes(x=x, y=y), color='blue', linetype='dashed')
# summary statistics
mean_mu_gibbs <- mean(mu_samps_gibbs)
mean_sigma2_gibbs <- mean(sigma2_samps_gibbs)
list(mean_mu_gibbs = mean_mu_gibbs,
mean_mu_analytical = mu_n,
mean_sigma2_gibbs = mean_sigma2_gibbs,
mean_sigma2_analytical = beta_n / (alpha_n - 1))$mean_mu_gibbs
[1] 1.729404
$mean_mu_analytical
[1] 1.734625
$mean_sigma2_gibbs
[1] 1.855577
$mean_sigma2_analytical
[1] 1.887219