library(ggplot2)
# Carregar os dados
dados <- read.csv("https://raw.githubusercontent.com/FCopf/prob-est-2026/refs/heads/main/_bibliography/mcelreath-2019/mcelreath-2019-data-sets/Howell1.csv",
sep = ";")
# Subset de adultos (age >= 18)
adultos <- dados[dados$age >= 18, ]
# Resumo descritivo das variáveis
str(adultos)
summary(adultos[, c("height", "weight", "age")])
# Estatísticas da variável de interesse
cat("n =", nrow(adultos), "\n")
cat("Média =", round(mean(adultos$height), 2), "cm\n")
cat("Mediana =", round(median(adultos$height), 2), "cm\n")
cat("DP =", round(sd(adultos$height), 2), "cm\n")
cat("Mín. =", round(min(adultos$height), 2), "cm\n")
cat("Máx. =", round(max(adultos$height), 2), "cm\n")Prática em R - Aula 05
Distribuição a posteriori no modelo Normal
1 Exploração inicial do conjunto de dados
O dataset Howell1 (McElreath 2020) registra dados antropométricos de 544 indivíduos !Kung San do deserto de Kalahari, coletados pelo antropólogo Nancy Howell. As variáveis disponíveis são height (altura em cm), weight (peso em kg), age (idade em anos) e male (indicador de sexo). Neste laboratório, o foco recai sobre a variável height dos 352 adultos com 18 anos ou mais.
O objetivo inicial é examinar a distribuição das alturas antes de qualquer ajuste de modelo, identificar as características da variável e avaliar se a Distribuição Normal é um modelo generativo plausível para esses dados.
Código
1.1 Visualização da distribuição
Código
# Histograma com curva de densidade e curva Normal teórica sobreposta
media_h <- mean(adultos$height)
dp_h <- sd(adultos$height)
ggplot(adultos, aes(x = height)) +
geom_histogram(aes(y = after_stat(density)), bins = 30,
fill = "steelblue", color = "white",
linewidth = 0.2, alpha = 0.7) +
geom_density(color = "steelblue4", linewidth = 1) +
stat_function(fun = dnorm,
args = list(mean = media_h, sd = dp_h),
color = "#e6a073", linewidth = 1, linetype = "dashed") +
labs(x = "Altura (cm)", y = "Densidade",
title = "Distribuição das alturas — adultos !Kung San",
subtitle = paste0("n = ", nrow(adultos),
" | média = ", round(media_h, 1),
" cm | dp = ", round(dp_h, 1), " cm")) +
theme_minimal(base_size = 12)2 Distribuições a priori e checagem preditiva a priori
Antes de observar os dados como evidência para estimar os parâmetros, é necessário especificar as distribuições a priori para \(\mu\) e \(\sigma\). As distribuições a priori expressam o conhecimento disponível sobre os parâmetros antes de qualquer dado ser incorporado ao modelo.
O modelo generativo para alturas de adultos é:
\[Y \sim \text{Normal}(\mu,\, \sigma)\] \[\mu \sim \text{Normal}(160,\, 20)\] \[\sigma \sim \text{Exponencial}(0{,}1)\]
A distribuição a priori \(\text{Normal}(160, 20)\) para \(\mu\) concentra a probabilidade em uma faixa de alturas biologicamente razoável para adultos humanos, cobrindo com probabilidade substancial o intervalo de 120 a 200 cm. A distribuição a priori \(\text{Exponencial}(0{,}1)\) para \(\sigma\) garante que o desvio padrão permaneça estritamente positivo e concentra a probabilidade abaixo de 30 cm, com valor esperado de 10 cm.
A checagem preditiva a priori verifica se as distribuições a priori, tomadas em conjunto, geram dados com características compatíveis com o fenômeno estudado. Para isso, ajusta-se o modelo sem incorporar os dados observados como evidência, amostrando exclusivamente das distribuições a priori especificadas.
Código
library(brms)
# Definição explícita das distribuições a priori
prioris <- c(
prior(normal(160, 20), class = Intercept), # priori para mu
prior(exponential(0.1), class = sigma) # priori para sigma
)
# Ajuste com sample_prior = "only": amostra apenas das distribuições a priori
fit_prior <- brm(
formula = height ~ 1,
family = gaussian(),
prior = prioris,
data = adultos,
sample_prior = "only",
chains = 4,
iter = 1000,
warmup = 500,
refresh = 0
)2.1 Visualização da distribuição preditiva a priori
Código
# Checagem preditiva a priori: distribuição simulada vs. dados observados
pp_check(fit_prior, ndraws = 100) +
labs(title = "Checagem preditiva a priori",
x = "Altura (cm)", y = "Densidade") +
xlim(-50, 400) +
theme_minimal(base_size = 12)3 Ajuste do modelo com brms
Com as distribuições a priori verificadas, o modelo é ajustado incorporando os dados observados. O brms compila o modelo em C++ e utiliza HMC para amostrar da distribuição a posteriori dos parâmetros. O resultado é um conjunto de amostras da distribuição a posteriori que resume o que o modelo aprendeu sobre \(\mu\) e \(\sigma\) à luz dos dados.
Código
# Ajuste do modelo com os dados observados
fit <- brm(
formula = height ~ 1,
family = gaussian(),
prior = prioris,
data = adultos,
chains = 4,
iter = 1000,
warmup = 500,
refresh = 0
)
# Visualizar o sumário do ajuste
summary(fit)4 Distribuições a posteriori dos parâmetros
A distribuição a posteriori é o produto central da estimação bayesiana. Ela expressa a incerteza residual sobre cada parâmetro após combinar as distribuições a priori com as evidências dos dados. Nesta seção, os parâmetros \(\mu\) e \(\sigma\) são explorados por meio de resumos numéricos e visualizações.
4.1 Resumo numérico dos parâmetros
Código
library(posterior)
# Extrair amostras da distribuição a posteriori em formato tidy
amostras <- as_draws_df(fit)
# Resumo detalhado: média, dp e intervalos de credibilidade de 89%
summarise_draws(
amostras,
mean, median, sd,
~quantile(.x, c(0.055, 0.945)),
.filter = ~grepl("b_Intercept|sigma", .x)
)
# Intervalo de credibilidade de 89% via posterior_interval()
posterior_interval(fit, prob = 0.89,
pars = c("b_Intercept", "sigma"))4.2 Visualização das distribuições marginais a posteriori
Código
library(bayesplot)
library(ggplot2)
library(patchwork)
# Distribuições marginais a posteriori para mu e sigma
p_mu <- ggplot(amostras, aes(x = b_Intercept)) +
geom_histogram(aes(y = after_stat(density)), bins = 50,
fill = "steelblue", color = "white",
linewidth = 0.2, alpha = 0.7) +
geom_density(color = "steelblue4", linewidth = 1) +
geom_vline(xintercept = posterior_interval(fit, prob = 0.89,
pars = "b_Intercept"),
linetype = "dashed", color = "gray40") +
labs(x = expression(mu ~ "(cm)"), y = "Densidade",
title = expression("Distribuição a posteriori de " ~ mu)) +
theme_minimal(base_size = 12)
p_sigma <- ggplot(amostras, aes(x = sigma)) +
geom_histogram(aes(y = after_stat(density)), bins = 50,
fill = "orange", color = "white",
linewidth = 0.2, alpha = 0.7) +
geom_density(color = "darkorange4", linewidth = 1) +
geom_vline(xintercept = posterior_interval(fit, prob = 0.89,
pars = "sigma"),
linetype = "dashed", color = "gray40") +
labs(x = expression(sigma ~ "(cm)"), y = "Densidade",
title = expression("Distribuição a posteriori de " ~ sigma)) +
theme_minimal(base_size = 12)
p_mu + p_sigma4.3 Distribuição a posteriori conjunta
Código
# Gráfico de dispersão das amostras conjuntas (mu, sigma)
ggplot(amostras, aes(x = b_Intercept, y = sigma)) +
geom_point(alpha = 0.15, color = "#1a9988", size = 0.8) +
geom_density_2d(color = "gray30", linewidth = 0.4) +
labs(x = expression(mu ~ "(cm)"), y = expression(sigma ~ "(cm)"),
title = "Distribuição a posteriori conjunta de µ e σ") +
theme_minimal(base_size = 12)5 Distribuição preditiva da posteriori
A distribuição a posteriori dos parâmetros descreve o que o modelo aprendeu sobre \(\mu\) e \(\sigma\). A distribuição preditiva da posteriori vai além: ela descreve a distribuição de novas alturas \(\tilde{y}\), propagando simultaneamente a variabilidade individual das alturas e a incerteza residual sobre os parâmetros.
A checagem preditiva da posteriori verifica se os dados que o modelo consegue gerar são compatíveis com os dados que foram realmente observados. Essa comparação é uma das ferramentas centrais para avaliar a adequação do modelo.
5.1 Checagem preditiva da posteriori
Código
# Checagem preditiva da posteriori: sobreposição de distribuições simuladas
# (linhas azul-claras) sobre os dados observados (linha escura)
pp_check(fit, ndraws = 100) +
labs(title = "Checagem preditiva da posteriori — modelo Normal",
x = "Altura (cm)", y = "Densidade") +
theme_minimal(base_size = 12)
# Checagem alternativa: comparação de estatísticas resumo
pp_check(fit, type = "stat", stat = "mean", ndraws = 1000) +
labs(title = "Distribuição preditiva da média a posteriori",
x = "Média simulada (cm)") +
theme_minimal(base_size = 12)
pp_check(fit, type = "stat", stat = "sd", ndraws = 1000) +
labs(title = "Distribuição preditiva do DP a posteriori",
x = "Desvio padrão simulado (cm)") +
theme_minimal(base_size = 12)5.2 Predição para novas observações
Código
# Gerar amostras da distribuição preditiva da posteriori
y_pred <- posterior_predict(fit, ndraws = 4000)
# Converter para vetor (todas as predições)
y_pred_vec <- as.vector(y_pred)
# Comparar dados observados com predições
dados_comp <- data.frame(
valor = c(adultos$height, y_pred_vec),
fonte = c(rep("Observado", nrow(adultos)),
rep("Preditiva da posteriori", length(y_pred_vec)))
)
ggplot(dados_comp, aes(x = valor, fill = fonte)) +
geom_histogram(aes(y = after_stat(density)), bins = 40,
alpha = 0.5, color = "white",
linewidth = 0.2, position = "identity") +
scale_fill_manual(values = c("Observado" = "steelblue",
"Preditiva da posteriori" = "#e6a073")) +
labs(x = "Altura (cm)", y = "Densidade", fill = NULL,
title = "Dados observados e distribuição preditiva da posteriori") +
theme_minimal(base_size = 12) +
theme(legend.position = "top")6 Alteração das distribuições a priori e sensibilidade da posteriori
A inferência bayesiana combina o conhecimento prévio (distribuições a priori) com as evidências dos dados (verossimilhança) para produzir a distribuição a posteriori. Com amostras grandes, os dados tendem a dominar as distribuições a priori. Com amostras pequenas ou distribuições a priori fortemente informativas, a influência das distribuições a priori é mais perceptível.
Esta seção explora como a escolha das distribuições a priori afeta a distribuição a posteriori. Três modelos são comparados:
- Modelo fracamente informativo: \(\mu \sim \text{Normal}(160, 20)\) (distribuição a priori original)
- Modelo fortemente informativo: \(\mu \sim \text{Normal}(160, 1)\) (distribuição a priori concentrada em 160 cm)
- Modelo com priori deslocada: \(\mu \sim \text{Normal}(185, 5)\) (distribuição a priori incompatível com os dados)
Código
# Modelo com distribuição a priori fortemente informativa (muito estreita)
fit_info <- update(
fit,
prior = c(
prior(normal(160, 1), class = Intercept),
prior(exponential(0.1), class = sigma)
),
refresh = 0
)
# Modelo com distribuição a priori deslocada (incompatível com os dados)
fit_deslocada <- update(
fit,
prior = c(
prior(normal(185, 5), class = Intercept),
prior(exponential(0.1), class = sigma)
),
refresh = 0
)
# Resumo dos três modelos
cat("=== Distribuição a priori fracamente informativa ===\n")
posterior_interval(fit, prob = 0.89, pars = "b_Intercept")
cat("=== Distribuição a priori fortemente informativa ===\n")
posterior_interval(fit_info, prob = 0.89, pars = "b_Intercept")
cat("=== Distribuição a priori deslocada ===\n")
posterior_interval(fit_deslocada, prob = 0.89, pars = "b_Intercept")6.1 Comparação visual das distribuições a posteriori
Código
library(posterior)
# Extrair amostras dos três modelos
am_fraca <- as_draws_df(fit)$b_Intercept
am_info <- as_draws_df(fit_info)$b_Intercept
am_deslocada <- as_draws_df(fit_deslocada)$b_Intercept
# Organizar em um único data frame
comp_post <- data.frame(
mu = c(am_fraca, am_info, am_deslocada),
model = rep(c("Priori fraca\nNormal(160, 20)",
"Priori informativa\nNormal(160, 1)",
"Priori deslocada\nNormal(185, 5)"),
each = length(am_fraca))
)
ggplot(comp_post, aes(x = mu, fill = model, color = model)) +
geom_density(alpha = 0.35, linewidth = 0.9) +
geom_vline(xintercept = mean(adultos$height),
linetype = "dashed", color = "black", linewidth = 0.8) +
scale_fill_manual(values = c("#1a9988", "#2c5f7c", "#e6a073")) +
scale_color_manual(values = c("#1a9988", "#2c5f7c", "#e6a073")) +
labs(x = expression(mu ~ "(cm)"), y = "Densidade",
fill = "Modelo", color = "Modelo",
title = "Comparação das distribuições a posteriori de µ",
subtitle = "Linha tracejada = média amostral dos dados") +
theme_minimal(base_size = 12) +
theme(legend.position = "right")