Lab on Binomial model
Bayesian Analysis of Binomial Data
Exercises on Bayesian inference with binomial data, taken from the Bayesian Data Analysis course site (associated to BDA textbook).
Visualization by ggplot2
Probabilità di una nascita femminile data la condizione placenta previa
(BDA3 p. 37).
L’a posteriori è una Beta(438,544)
# seq creates evenly spaced values
df1 <- data.frame(theta = seq(0.375, 0.525, 0.001))
a <- 438
b <- 544
# dbeta computes the posterior density
df1$p <- dbeta(df1$theta, a, b)
Calcoliamo anche l’intervallo centrale del 95%
# seq creates evenly spaced values from 2.5% quantile to 97.5% quantile (i.e., 95% central interval)
# qbeta computes the value for a given quantile given parameters a and b
df2 <- data.frame(theta = seq(qbeta(0.025, a, b), qbeta(0.975, a, b), length.out = 100))
# compute the posterior density
df2$p <- dbeta(df2$theta, a, b)
Si disegni l’a posteriori (Beta(438,544)) e la linea verticale per la media della popolazione (48.8%)
ggplot2
One of the key ideas behind ggplot2 is that it allows you to easily iterate, building up a complex plot a layer at a time. Each layer can come from a different dataset and have a different aesthetic mappings, making it possible to create sophisticated plots that display data from multiple sources.
ggplot(mapping = aes(theta, p)) +
geom_line(data = df1) +
# Add a layer of colorized 95% posterior interval
geom_area(data = df2, aes(fill='1')) +
# Add the proportion of girl babies in general population
geom_vline(xintercept = 0.488, linetype='dotted', linewidth=1.25) +
# Decorate the plot a little
labs(title='Uniform prior -> Posterior is Beta(438,544)',x=expression(theta), y = '') +
scale_y_continuous(expand = c(0, 0.1), breaks = NULL) +
scale_fill_manual(values = 'lightblue', labels = '95% posterior interval') +
theme(legend.position = 'bottom', legend.title = element_blank())
change from ggplot2 3.4.0
Warning: Using
size
aesthetic for lines was deprecated in ggplot2 3.4.0. ℹ Please uselinewidth
instead.
Effetto di diverse a priori in un modello binomiale
Effetto dell’a priori e confronto delle a posteriori con valori dei parametri differenti per le a priori beta
Oltre a ggplot2 per la visualizzazione, tidyr
è usato
per lavorare sui data frame
Dati osservati: 437 femmine e 543 maschi
La densità viene valutata nei punti equamente distribuiti tra 0.375 e 0.525
A posteriori con Beta(1,1), ie. a priori uniforme
Tre scelte differenti per le a priori
Beta(\(0.488*2\),\((1-0.488)*2\))
Beta(\(0.488*20\),\((1-0.488)*20\))
Beta(\(0.488*200\),\((1-0.488)*200\))
n <- c(2, 20, 200) # conteggi a priori
apr <- 0.488 # prop di successo a priori
# helperf ritorna, dati un numero di osservazioni a priori, una prop di successo a priori,
# un numero di successi e fallimenti osservati e un dataframe con i valori per theta,
# un dataframe nuovo con valori a priori e a posteriori calcolati nei punti theta.
#
helperf <- function(n, apr, a, b, df)
cbind(df, pr = dbeta(df$theta, n*apr, n*(1-apr)), po = dbeta(df$theta, n*apr + a, n*(1-apr) + b), n = n)
# lapply the above function over prior counts n, then bind by row, and lastly gather results into key-value pairs.
df2 <- lapply(n, helperf, apr, a, b, df1) %>% do.call(rbind, args = .) %>%
gather(key = grp, value = p, -c(theta, n), factor_key = T)
df2 %>% head; df2 %>% tail
theta n grp p
1 0.375 2 pu 0.0008507679
2 0.376 2 pu 0.0011418738
3 0.377 2 pu 0.0015257278
4 0.378 2 pu 0.0020295190
5 0.379 2 pu 0.0026876416
6 0.380 2 pu 0.0035433725
theta n grp p
1354 0.520 200 po 0.0006885263
1355 0.521 200 po 0.0005006071
1356 0.522 200 po 0.0003622430
1357 0.523 200 po 0.0002608721
1358 0.524 200 po 0.0001869727
1359 0.525 200 po 0.0001333673
# add correct labels for plotting
df2$title <- factor(paste0('alpha/(alpha+beta)=0.488, alpha+beta=',df2$n))
levels(df2$grp)
[1] "pu" "pr" "po"
levels(df2$grp) <- c('Posterior with unif prior', 'Prior', 'Posterior')
df2 %>% head
theta n grp p
1 0.375 2 Posterior with unif prior 0.0008507679
2 0.376 2 Posterior with unif prior 0.0011418738
3 0.377 2 Posterior with unif prior 0.0015257278
4 0.378 2 Posterior with unif prior 0.0020295190
5 0.379 2 Posterior with unif prior 0.0026876416
6 0.380 2 Posterior with unif prior 0.0035433725
title
1 alpha/(alpha+beta)=0.488, alpha+beta=2
2 alpha/(alpha+beta)=0.488, alpha+beta=2
3 alpha/(alpha+beta)=0.488, alpha+beta=2
4 alpha/(alpha+beta)=0.488, alpha+beta=2
5 alpha/(alpha+beta)=0.488, alpha+beta=2
6 alpha/(alpha+beta)=0.488, alpha+beta=2
Grafico delle distribuzioni
ggplot(data = df2) +
geom_line(aes(theta, p, color = grp)) +
geom_vline(xintercept = apr, linetype = 'dotted') +
facet_wrap(~ title, ncol = 1) +
labs(x = '', y = '') +
scale_y_continuous(breaks = NULL) +
theme(legend.position = 'bottom', legend.title = element_blank())
Inferenza basata sulla simulazione
Simuliamo campioni da una Beta(438,544), disegniamo un istogramma (con quantili), e facciamo lo stesso per una variabile trasformata.
Campioniamo dalla a posteriori Beta(438,544). Otteniamo tutte le estrazioni in una volta e salviamole in un vettore ‘theta’
Calcoliamo l’odds ratio per tutte le estrazioni
Calcoliamo i quantili 2.5% e 97.5% aprossimati usando i campioni
Istogrammi con 30 bins per theta e phi
# merge the data into one data frame for plotting
df1 <- data.frame(phi,theta) %>% gather()
#df1 %>% head
# merge quantiles into one data frame for plotting
df2 <- data.frame(phi = phiq, theta = thetaq) %>% gather()
#df2
ggplot() +
geom_histogram(data = df1, aes(value), bins = 30) +
geom_vline(data = df2, aes(xintercept = value), linetype = 'dotted', linewidth = 1.25) +
facet_wrap(~key, ncol = 1, scales = 'free_x') +
labs(x = '', y = '') +
scale_y_continuous(breaks = NULL)
Se vogliamo aggoiungere la densità
ggplot(data = df1, aes(value)) +
geom_histogram(aes(y = after_stat(density)), fill="white", col="black", bins = 30) +
geom_density(col = 2, fill = 2, alpha=.2) +
geom_vline(data = df2, aes(xintercept = value), linetype = 'dotted', linewidth = 1.25) +
facet_wrap(~key, ncol = 1, scales = 'free') +
labs(x = '', y = '') +
scale_y_continuous(breaks = NULL)
Grid e inverse-cdf sampling
Campionamento con griglia e con l’inversa della funzione di ripartizione
- Calcoliamo la distribuzione a posteriori su una griglia discreta di punti moltiplicando la verosimiglianza e un’a priori non coniugata in ogni punto e poi normalizzando sui punti.
- Simuliamo campioni dalla distribuzione a posteriori non standard risultante utilizzando l’inversa della cdf e la griglia discreta.
A posteriori con osservazioni (437,543) e a priori uniforme (Beta(1,1))
Calcoliamo la densità di un’a priori non-coniugata nei punti discreti di una griglia.
E.g., un’a priori lineare a pezzi con una certa % di probabilità al di fuori dell’intervallo (0.388, 0.588) (si veda la figura 2.4 in BDA3)
pp <- rep(1, nrow(df1))
pi <- sapply(c(0.388, 0.488, 0.588), function(pi) which(df1$theta == pi))
pi
[1] 289 389 489
pm <- 11
pp[pi[1]:pi[2]] <- seq(1, pm, length.out = length(pi[1]:pi[2])) #%>% print
pp[pi[3]:pi[2]] <- seq(1, pm, length.out = length(pi[3]:pi[2])) #%>% print
Normalizziamo la a priori
Calcoliamo l’a posteriori non-normalizzata e non-coniugata sulla griglia, quindi la normalizziamo
Disegniamo l’a posteriori con a priori uniforme, l’a priori non-coniugata e la corrispondente a posteriori non-coniugata
# gather the data frame into key-value pairs
# and change variable names for plotting
df2 <- gather(df1, grp, p, -theta, factor_key = T) #%>%
levels(df2$grp) <- c('Posterior with uniform prior', 'Non-conjugate prior', 'Non-conjugate posterior')
ggplot(data = df2) +
geom_line(aes(theta, p)) +
facet_wrap(~grp, ncol = 1, scales = 'free_y') +
coord_cartesian(xlim = c(0.35,0.6)) +
scale_y_continuous(breaks=NULL) +
labs(x = '', y = '')
Inverse cdf sampling
calcoliamo la densità cumulata (funzione di ripartizione) sulla griglia
Campioniamo dalla distr uniforme U(0,1)
# set.seed(seed) is used to set seed for the random number generator
set.seed(2601)
# runif(k) returns k uniform random numbers from interval [0,1]
r <- runif(10000)
Campionamento tramite l’inversa della cdf
# function to find the smallest value theta at which the cumulative sum of the posterior densities is greater than r.
invcdf <- function(r, df) df$theta[sum(df$cs_po < r) + 1]
# sapply function for each sample r. The returned values s are now random draws from the distribution.
s <- sapply(r, invcdf, df1)
Creiamo tre grafici: p1 è l’a posteriori, p2 è la cdf dell’a posteriori e p3 è l’istogramma delle estrazioni dall’a posteriori (estratte usando l’inversa-cdf)
p1 <- ggplot(data = df1) +
geom_line(aes(theta, nc_po)) +
coord_cartesian(xlim = c(0.35, 0.6)) +
labs(title = 'Non-conjugate posterior', x = '', y = '') +
scale_y_continuous(breaks = NULL)
p2 <- ggplot(data = df1) +
geom_line(aes(theta, cs_po)) +
coord_cartesian(xlim = c(0.35, 0.6)) +
labs(title = 'Posterior-cdf', x = '', y = '') +
scale_y_continuous(breaks = NULL)
p3 <- ggplot() +
geom_histogram(aes(s, y = after_stat(density)), binwidth = 0.003) +
geom_line(aes(s, y = after_stat(density)), stat = "bin", binwidth = 0.003, col='red') +
coord_cartesian(xlim = c(0.35, 0.6)) +
labs(title = 'Histogram of posterior samples', x = '', y = '') +
scale_y_continuous(breaks = NULL)
# combine the plots
grid.arrange(p1, p2, p3)