R: Bayesian Statistics

1
2
3
4
5
6
7
8
# funzioni
# https://mran.microsoft.com/snapshot/2017-12-11/web/packages/TeachBayes/TeachBayes.pdf
source("https://raw.githubusercontent.com/AlbGri/AlbGri.github.io/master/assets/files/R/LearningBayes.R")

# lib
suppressMessages(library(ggplot2))
suppressMessages(library(gridExtra))
suppressMessages(library(dplyr))

Introduction

Probabilità

1
2
areas <- c(2, 1, 2, 1, 2)
spinner_plot(areas)

1
2
3
4
# distribuzione di probabilità
df <- data.frame(Region = 1:5, areas,
                Probability = areas / sum(areas))
df
A data.frame: 5 × 3
RegionareasProbability
<int><dbl><dbl>
120.250
210.125
320.250
410.125
520.250

Stima classica

\[P(\mbox{dispari})=0.25+0.25+0.25=0.75\]
1
df %>% filter(Region %in% c(1,3,5))
A data.frame: 3 × 3
RegionareasProbability
<int><dbl><dbl>
120.25
320.25
520.25
\[P(\mbox{Maggiore di 3})=0.125+0.25=0.375\]
1
df %>% filter(Region > 3)
A data.frame: 2 × 3
RegionareasProbability
<int><dbl><dbl>
410.125
520.250

Stima con simulazione

1
2
3
# genero un campione casuale di 10 osservazioni delle 5 regioni con le rispettive probabilità di estrazione
ten_spins <- spinner_data(areas, 10)
ten_spins

1 5 5 5 2 1 1 3 3 4

1
2
3
# genero un campione casuale di 10000 osservazioni delle 5 regioni con le rispettive probabilità di estrazione
many_spins <- spinner_data(areas, 10000)
bar_plot(many_spins)

1
2
3
4
5
# distribuzione di frequenza
S <- data.frame(Region = many_spins) %>%
    group_by(Region) %>%
    summarise(N=n(), .groups = 'drop_last')
S
A tibble: 5 × 2
RegionN
<int><int>
12499
21238
32512
41224
52527
\[P(\mbox{Region}=1)\]
1
S %>% filter(Region==1) %>% sum() / 1000

2.5

Bayes’ rule

Si hanno 4 spinner, ciascuno diviso in 3 colori (Rosso, Verde e Blu).
Obiettivo: se so che è uscito Rosso, quale spinner mi aspetto sia stato utilizzato?

1
2
bayes_df <- data.frame(Model = paste("Spinner", c("A", "B", "C", "D")))
bayes_df
A data.frame: 4 × 1
Model
<chr>
Spinner A
Spinner B
Spinner C
Spinner D

Distribuzione a priori

Non sapendo se alcuni di questi spinner vengono scelti più o meno facilmente, assegno equiprobabilità per la scelta dello spinner.

1
2
3
# distribuzione a priori
bayes_df$Prior <- rep(0.25, 4)
bayes_df
A data.frame: 4 × 2
ModelPrior
<chr><dbl>
Spinner A0.25
Spinner B0.25
Spinner C0.25
Spinner D0.25

Verosimiglianza

Conosciamo la probabilità di estrazione del colore Rosso per ciascun spinner

1
2
3
# probabilità di ottenere rosso
bayes_df$Likelihood <- round(c(1/3, 1/2, 1/4, 1/6), 2)
bayes_df
A data.frame: 4 × 3
ModelPriorLikelihood
<chr><dbl><dbl>
Spinner A0.250.33
Spinner B0.250.50
Spinner C0.250.25
Spinner D0.250.17

Distribuzione a posteriori

“Turn the Bayesian Crank” significa calcolare le probabilità a posteriori usando la regola di Bayes

1
2
3
# ne fa il prodotto e normalizza rispetto la somma
bayes_df <- bayesian_crank(bayes_df)
bayes_df
A data.frame: 4 × 5
ModelPriorLikelihoodProductPosterior
<chr><dbl><dbl><dbl><dbl>
Spinner A0.250.330.08250.264
Spinner B0.250.500.12500.400
Spinner C0.250.250.06250.200
Spinner D0.250.170.04250.136


Quindi, mi aspetto che lo spinner \(B\) sia stato quello utilizzato (in quanto l’a priori, aggiornata con la verosimiglianza, cioè l’a posteriori, fa emergere che lo spinner \(B\) sia il più probabile).

1
2
# confronto distribuzioni
prior_post_plot(bayes_df)

Sequential Bayes

Se si continua, l’a posteriori sarà la nuova distribuzione a priori.
Cosa accade se ora se si estrae il blu?

1
2
3
# nuova priori
bayes_df2 <- bayes_df %>% select(Model, Posterior) %>% rename(Prior=Posterior)
bayes_df2
A data.frame: 4 × 2
ModelPrior
<chr><dbl>
Spinner A0.264
Spinner B0.400
Spinner C0.200
Spinner D0.136
1
2
3
# verosimiglianza del blu
bayes_df2$Likelihood <- round(c(1/3, 1/4, 1/2, 2/3), 2)
bayes_df2
A data.frame: 4 × 3
ModelPriorLikelihood
<chr><dbl><dbl>
Spinner A0.2640.33
Spinner B0.4000.25
Spinner C0.2000.50
Spinner D0.1360.67
1
2
3
# posteriori: bayesian crank
bayes_df2 <- bayesian_crank(bayes_df2)
bayes_df2
A data.frame: 4 × 5
ModelPriorLikelihoodProductPosterior
<chr><dbl><dbl><dbl><dbl>
Spinner A0.2640.330.087120.2303299
Spinner B0.4000.250.100000.2643824
Spinner C0.2000.500.100000.2643824
Spinner D0.1360.670.091120.2409052

Ora lo spinner che più probabilmente è stato usato non è solo il \(B\) ma anche il \(C\)

1
2
# confronto distribuzioni
prior_post_plot(bayes_df2)

1
2
# clear environment
rm(list=ls())

Distribuzione a priori discreta

Distribuzione a priori (proporzione)

Sia \(p\) la proporzione di individui positivi
\(p \in \left\{0.3,0.4,...,0.8\right\}\)
La nostra sensibilità e/o conoscenza di dominio ci porta ad affermare che \(0.5\) (stessa numerosità di positivi e negativi) e \(0.6\) sono le proporzioni più plausibili per questo studio, due volte più probabili rispetto gli altri.

1
2
3
4
bayes_df <- data.frame(P = seq(0.3,0.8,by=0.1),
                      Weight = c(1,1,2,2,1,1),
                      Prior = c(1,1,2,2,1,1)/8)
bayes_df
A data.frame: 6 × 3
PWeightPrior
<dbl><dbl><dbl>
0.310.125
0.410.125
0.520.250
0.620.250
0.710.125
0.810.125

Verosimiglianza (Binomiale)

A seguito della raccolta empirica dei dati da un campione, si ottengono 12 positivi su 20.
L’esperimento è binomiale: la probabilità di 12 successi su 20, con probabilità di successo \(p\)
\(L={20\choose 12}p^{12}(1-p)^{8}\)

1
2
3
4
5
# verosimiglianza
bayes_df <- bayes_df %>% 
    mutate(Likelihood = round(dbinom(12, size=20, prob=bayes_df$P),3)) %>%
    select(P, Prior, Likelihood)
bayes_df
A data.frame: 6 × 3
PPriorLikelihood
<dbl><dbl><dbl>
0.30.1250.004
0.40.1250.035
0.50.2500.120
0.60.2500.180
0.70.1250.114
0.80.1250.022

Distribuzione a posteriori

1
2
3
# crank!
bayes_df <- bayesian_crank(bayes_df)
bayes_df
A data.frame: 6 × 5
PPriorLikelihoodProductPosterior
<dbl><dbl><dbl><dbl><dbl>
0.30.1250.0040.0005000.00516129
0.40.1250.0350.0043750.04516129
0.50.2500.1200.0300000.30967742
0.60.2500.1800.0450000.46451613
0.70.1250.1140.0142500.14709677
0.80.1250.0220.0027500.02838710
1
2
# confronto
prior_post_plot(bayes_df)

Inferenza Bayesiana

\(P(p>0.5)=?\)

1
bayes_df %>% select(P, Posterior)
A data.frame: 6 × 2
PPosterior
<dbl><dbl>
0.30.00516129
0.40.04516129
0.50.30967742
0.60.46451613
0.70.14709677
0.80.02838710
1
bayes_df %>% filter(P>0.5) %>% select(Posterior) %>% sum()

0.64

Distribuzione a priori continua

Distribuzione a priori (Beta)

\(p^{a-1}(1-p)^{b-1}\) con \(p \in \Re | 0< p< 1\)
Rappresenta la conoscenza a priori su \(p\)
Non è semplice identificare i parametri \(a\) e \(b\).
Per un semplice esempio, ipotizzo \(a=7\) e \(b=10\)

1
2
# probabilità che il parametro p sia tra 0.8 e 0.4
pbeta(0.8, 7, 10) - pbeta(0.4, 7, 10)

0.526926535983103

1
beta_area(0.4, 0.8, c(7, 10))

1
2
# il valore mediano risulta
qbeta(0.5, 7, 10)

0.408226501324901

1
beta_quantile(0.5, c(7, 10))

Posso determinare una stima dei parametri a priori \(a\) e \(b\), ipotizzando due valori plausibili per il 50-esimo e 90-esimo percentile.
[TO DO] AGGIUNGERE FORMULA PER OTTENERE I PARAMETRI DAI QUANTILI IPOTIZZATI
In base alla propria sensibilità e/o conoscenza di dominio, ipotizzo i due suddetti valori, tenendo presente che, ad esempio, un valore del 90-esimo percentile pari a 0.80, indica che sono sicuro all’90% che \(p\) sia più piccolo di 0.8.

1
2
3
4
5
6
7
# specifico i quantili 0.5 e 0.9
p50 <- list(x=0.55, p=0.5)
p90 <- list(x=0.80, p=0.9)

# trovo la corrispondente curva beta
parametri_priori <- beta.select(p50, p90)
parametri_priori # rispettivamente a e b

3.06; 2.56

1
2
# plot beta a priori
beta_draw(parametri_priori)

1
2
# calcolo l'intervallo di probabilità 50%
beta_interval(0.5, parametri_priori)

1
2
# calcolo la probabilità che p sia minore di 0.4
beta_area(0, 0.4, parametri_priori)

Verosimiglianza (Binomiale)

A seguito della raccolta empirica dei dati da un campione, si ottengono 12 positivi su 20.
L’esperimento è binomiale: la probabilità di 12 successi su 20, con probabilità di successo \(p\)
\(L={20\choose 12}p^{12}(1-p)^{8}\)

Distribuzione a posteriori (Beta)

\(\mbox{Posteriori}\propto \mbox{Prori} \times \mbox{Verosimiglianza}\)
\(\mbox{Posteriori}\propto [p^{3.06}(1-p)^{2.56-1}]\times [p^{12}(1-p)^8]=p^{15.06-1}(1-p)^{10.56-1}\equiv \mbox{Densità }\mathrm{B}(15.06,10.56)\)
Quindi si ha \(\bigg\{\mbox{Priori}=\mathrm{B}\big(a,b\big)\bigg\}\times \bigg\{\mbox{Verosimiglianza}=\mathrm{Bin}\Big(p=\frac{s}{s+f}\Big)\bigg\}=\bigg\{\mbox{Posteriori}=\mathrm{B}\big(a+s,b+f\big)\bigg\}\)

1
2
3
data <- c(12,8)
parametri_posteriori <- parametri_priori + data
parametri_posteriori

15.06; 10.56

1
2
# confronto priori e posteriori
beta_prior_post(parametri_priori, parametri_posteriori)

Inferenza Bayesiana

Test d’ipotesi

Valutiamo l’ipotesi che l’80% è positivo \(H:P>0.80\)

1
1 - pbeta(0.8, parametri_posteriori[1], parametri_posteriori[2])

0.00818530232747894

1
beta_area(0.8, 1, parametri_posteriori)

Intervalli di credibilità

Un intervallo di credibilità al 90%, è un intervallo che contiene al 90% la probabilità di contenere il parametro.

1
2
# intervallo equi-tails
beta_interval(0.90, parametri_posteriori)

La probabilità che \(p\) sia nell’intervallo \((0.427,0.741)\) è esattamente 0.9.

Intervalli di confidenza

Nell’approccio classico (frequentista), l’intervallo di confidenza è basato sulla condizione degli esperimenti ripetuti.
Secondo il metodo “aggiungi 2 successi e 2 insuccessi” di Agresti e Coull, dati \(y\) successi e un campione di dimensione \(n\), l’intervallo 90% è:
\((\hat{p}-1.645se,\hat{p}+1.645se)\)
con
\(\hat{p}=\frac{y+2}{n+4}\) e \(se=\sqrt{\frac{\hat{p}(1-\hat{p})}{n+4}}\)

1
classical_binom_ci(12, 20, 0.90)

0.417804211107709; 0.748862455558958

L’intervallo bayesiano è più stretto dell’intervallo di confidenza, è prevedibile in quanto è più preciso perché combina i dati con l’informazione a priori.

Simulazioni dalla a-posteriori

1
2
# genero 1000 osservazioni dalla densità beta con i parametri precedenti
sim_p <- rbeta(1000, parametri_posteriori[1], parametri_posteriori[2])
1
2
3
# valuto la loro distribuzione
hist(sim_p, freq=FALSE)
curve(dbeta(x, parametri_posteriori[1], parametri_posteriori[2]), add=TRUE, col="red", lwd=3)

1
2
3
# probabilità che p < 0.5 usando la simulazione
prob <- sum(sim_p < 0.5)/1000
prob

0.192

1
2
# probabilità esatta
pbeta(0.5, parametri_posteriori[1], parametri_posteriori[2])

0.182415035367533

1
2
# quantili campionari
quantile(sim_p, c(0.05, 0.95))

5%: 0.425741818823082; 95%: 0.737247520104539

Posterior of log odds ratio

Vogliamo ottenere l’intervallo al 90% di probabilità per \(\log{\frac{p}{1-p}}\)

1
sim_logit <- log(sim_p / (1-sim_p))
1
2
# distribuzione
hist(sim_logit, freq=FALSE)

1
2
# quantili campionari
quantile(sim_logit, c(0.10, 0.90))

10%:-0.15169200371894; 90%:0.86935740076806

1
2
# clear environment
rm(list=ls())

Normal sampling model (\(\sigma\) noto)

Distribuzione a priori (Uniforme Discreta)

Sia \(M\) una v.a. che modella i secondi necessari per calciare un rigore.
Ipotizzo un range tra 15 e 22 secondi, distribuito uniformemente (discreto).
\(M\sim\mathrm{U}[15,22]\)

1
2
bayes_df <- data.frame(M=15:22,Prior=rep(1/8,8))
prob_plot(bayes_df) + ylim(0,0.25)

Verosimiglianza (Normale)

1
2
3
4
# verosimiglianze "plausibili"
Models <- list(c(15,4), c(16,4), c(17,4), c(18,4), 
              c(19,4), c(20,4), c(21,4), c(22,4))
many_normal_plots(Models)

Si registrano 20 tiri in porta e si osserva che
il valore medio \(\hat{y}=17.2\)
lo standard error associato \(se=\frac{S}{\sqrt{n}}=\frac{4}{\sqrt{20}}=0.89\)

1
2
3
4
5
# collect data
ymean <- 17.2
se <- 4/sqrt(20)
bayes_df$Likelihood <- dnorm(ymean, mean=bayes_df$M, sd=se)
round(bayes_df, 3)
A data.frame: 8 × 3
MPriorLikelihood
<dbl><dbl><dbl>
150.1250.022
160.1250.181
170.1250.435
180.1250.299
190.1250.059
200.1250.003
210.1250.000
220.1250.000

Distribuzione a posteriori (Normale)

1
2
3
# calcolo posteriori
bayes_df <- bayesian_crank(bayes_df)
round(bayes_df,3)
A data.frame: 8 × 5
MPriorLikelihoodProductPosterior
<dbl><dbl><dbl><dbl><dbl>
150.1250.0220.0030.022
160.1250.1810.0230.181
170.1250.4350.0540.435
180.1250.2990.0370.299
190.1250.0590.0070.059
200.1250.0030.0000.003
210.1250.0000.0000.000
220.1250.0000.0000.000
1
2
# priori vs posteriori
prior_post_plot(bayes_df)

1
2
3
4
5
6
7
8
9
10
11
12
# quali range di valori ha almeno il 90% di probabilità
bayes_df %>% 
  arrange(desc(Posterior)) %>% 
  select(M, Posterior) %>% 
  head(3) %>%
  mutate(
    Posterior = round(Posterior,3),
    M = as.character(M)
  ) %>%
  as.data.frame() %>%
  # bind_rows(data.frame(M="Totale",Posterior=sum(.[,"Posterior"])))
  bind_rows(summarise_all(., ~ if (is.numeric(.)) sum(.) else "Totale"))
A data.frame: 4 × 2
MPosterior
<chr><dbl>
17 0.435
18 0.299
16 0.181
Totale0.915

Distribuzione a priori (Normale)

Assumiamo ora che la distribuzione a priori sia continua e segua una normale.
\(\mathscr{N}(M_0,S_0)\)
Con \(M_0\) rappresenta la migliore ipotesi di \(M\) e \(S_0\) indica quanto sono sicuro della ipotesi.

Un esperto suggerisce che \(M\) sia vicino a 18 secondi, e si avrà un valore piccolo per \(S_0\) (es \(0.1\)).
Un inesperto pensa che \(M\) sia vicino a 18 secondi, ma si avrà un valore elevato per \(S_0\) (es \(7\)).

Posso determinare una stima dei parametri a priori \(M_0\) e \(S_0\), ipotizzando due valori plausibili per il 50-esimo e 90-esimo percentile.
[TO DO] AGGIUNGERE FORMULA PER OTTENERE I PARAMETRI DAI QUANTILI IPOTIZZATI
Il quantile è un valore di \(M\) che indica la possibilità di essere inferiore di quel valore con una data probabilità.

In base alla propria sensibilità e/o conoscenza di dominio, ipotizzo i due suddetti valori

  • \(0.50\) quantile per M è \(18\) secondi (significa che è ugualmente probabile che un valore sia più alto o più basso di \(18\) secondi)
  • \(0.90\) quantile per M è \(20\) secondi (significa che la probabilità di ottenere un valore inferiore a \(20\) è del 90%)
1
2
3
4
# stima parametri dall'assegnazione di due quantili
parametri_priori <- lapply(normal.select(list(x=18, p=0.5),
              list(x=20, p=0.9)), function(x) round(x, 2))
parametri_priori
$mu
18
$sigma
1.56
1
2
# distribuzione a priori
normal_draw(parametri_priori)

1
2
# trovo il quantile 0.25 della priori
qnorm(0.25, parametri_priori$mu, parametri_priori$sigma)

16.9477959896941

1
normal_quantile(0.25, parametri_priori)

è ragionevole che \(P(M<16.95)=0.25\)? Se no, si perfezionano \(M_0\) e \(S_0\)

1
2
3
4
5
# assegno distribuzione a priori
bayes_df <- data.frame(M=15:22)
bayes_df <- bayes_df %>%
    mutate(Prior=round(dnorm(M, mean=parametri_priori$mu, sd=parametri_priori$sigma),3))
bayes_df
A data.frame: 8 × 2
MPrior
<int><dbl>
150.040
160.112
170.208
180.256
190.208
200.112
210.040
220.010

Verosimiglianza (Normale)

Si registrano 20 tiri in porta e si osserva che
il valore medio \(\hat{y}=17.2\)
lo standard error associato \(se=\frac{S}{\sqrt{n}}=\frac{4}{\sqrt{20}}=0.89\)

1
2
3
4
5
# verosimiglianza
parametri_verosimiglianza <- list(mu=17.2, sigma=0.89)
bayes_df <- bayes_df %>%
    mutate(Likelihood=dnorm(parametri_verosimiglianza$mu, mean=M, sd=parametri_verosimiglianza$sigma))
round(bayes_df,3)
A data.frame: 8 × 3
MPriorLikelihood
<dbl><dbl><dbl>
150.0400.021
160.1120.181
170.2080.437
180.2560.299
190.2080.058
200.1120.003
210.0400.000
220.0100.000

Distribuzione a posteriori (Normale)

\(\mbox{Posteriori}\propto \mbox{Prori} \times \mbox{Verosimiglianza}\)
Quindi si ha \(\bigg\{\mbox{Priori}=\mathscr{N}\big(M_0,S_0\big)\bigg\}\times \bigg\{\mbox{Verosimiglianza}=\mathscr{N}\big(M_1,S_1\big)\bigg\}=\bigg\{\mbox{Posteriori}=\mathscr{N}\big(M_{Post},S_{Post}\big)\bigg\}\)
con
\(P_k=\frac{1}{S_k^2}\)
\(M_{Post}=\mbox{W.AVG}(M;P)\)
\(S_{Post}=\frac{1}{\sqrt{\sum S}}\)

1
2
3
# aggiungo la precision ai parametri a priori
parametri_priori <- append(parametri_priori, list(precision=round(1/parametri_priori$sigma^2,2)))
parametri_priori
$mu
18
$sigma
1.56
$precision
0.41
1
2
3
# parametri verosimiglianza, con la sua precision
parametri_verosimiglianza <- append(parametri_verosimiglianza, list(precision=round(1/parametri_verosimiglianza$sigma^2,2)))
parametri_verosimiglianza
$mu
17.2
$sigma
0.89
$precision
1.26
1
2
3
4
5
6
7
8
9
10
11
# parametri posteriori, con la sua precision
parametri_posteriori <- list(
  mu = round(weighted.mean(x=c(parametri_priori$mu, 
                       parametri_verosimiglianza$mu), 
                   w=c(parametri_priori$precision, 
                       parametri_verosimiglianza$precision)),2),
  sigma = round(1/sqrt(sum(c(parametri_priori$precision, 
                       parametri_verosimiglianza$precision))),2),
  precision = sum(c(parametri_priori$precision, 
                    parametri_verosimiglianza$precision)))
parametri_posteriori
$mu
17.4
$sigma
0.77
$precision
1.67
1
2
3
4
5
6
# dati insieme
rbind(
  data.frame(fonte="parametri_priori",parametri_priori),
  data.frame(fonte="parametri_verosimiglianza",parametri_verosimiglianza), 
  data.frame(fonte="parametri_posteriori",parametri_posteriori)
  )
A data.frame: 3 × 4
fontemusigmaprecision
<chr><dbl><dbl><dbl>
parametri_priori 18.01.560.41
parametri_verosimiglianza17.20.891.26
parametri_posteriori 17.40.771.67
1
2
3
# funzione automatica calcolo posteriori normale
normal_update(as.numeric(parametri_priori[1:2]), 
              as.numeric(parametri_verosimiglianza[1:2]))

17.3964472827603; 0.773041159419683

1
2
3
4
# funzione automatica (estesa) calcolo posteriori normale
normal_update(as.numeric(parametri_priori[1:2]), 
              as.numeric(parametri_verosimiglianza[1:2]), 
             teach=TRUE)
A data.frame: 3 × 4
TypeMeanPrecisionStand_Dev
<chr><dbl><dbl><dbl>
Prior 18.000000.41091391.5600000
Data 17.200001.26246690.8900000
Posterior17.396451.67338070.7730412
1
2
3
# confronto grafico tra priori e posteriori
many_normal_plots(list(as.numeric(parametri_priori[1:2]),
                      as.numeric(parametri_posteriori[1:2])))

Inferenza Bayesiana

Test d’ipotesi

Valutiamo l’ipotesi che servano in media almeno 19 secondi per calciare
\(H:M\ge 19\)

Approccio classico

Test statistics \(Z=\frac{\bar{y}-19}{se}\)

1
2
3
# Z score
z <- (parametri_verosimiglianza$mu - 19)/parametri_verosimiglianza$sigma
z

-2.02247191011236

1
2
# p-value del z-score
pnorm(z)

0.0215638113390887

Con l’approccio classico si ha un p-value del 2% e si riufiuta l’ipotesi nulla.

Approccio Bayesiano

L’attuale opinione è rappresentata dalla posteriori
\(\mathscr{N}(17.4,0.77)\)

1
2
# probabilità che M>=19
1 - pnorm(19, parametri_posteriori$mu, parametri_posteriori$sigma)

0.0188582683438657

Ottengo un risultato simile al p-value, e anche in questo caso si rifiuta l’ipotesi nulla, o meglio dire che l’affermazione ipotizzata è improbabile che sia vera.

Simulazioni dalla a-posteriori

Siamo interessati a conoscere il tempo medio (e un suo intervallo di credibilità)

1
2
# distribuzione a posteriori
normal_draw(parametri_posteriori)

1
2
# simulation
M_sim <- rnorm(1000, mean=parametri_posteriori$mu, sd=parametri_posteriori$sigma)
1
2
3
4
# intervallo di credibilità a 80%
# round(quantile(M_sim, c(0.10, 0.90)),1)
normal_interval(0.80, parametri_posteriori)
# la probabilità che M sia in questo intervallo è dell'80%

Bayesian Predictions

Per prevedere il prossimo tempo \(y\) serve determinare la predictive density di \(y\).
Non conosciamo il vero valore di \(M\) ma conosciamo la distribuzione a posteriori \(\mathscr{N}(17.4,0.77)\)
Step

  1. si simula un valore \(M\) da \(\mathscr{N}(17.4,0.77)\)
  2. si simula un valore \(y\) dalla densità \(\mathscr{N}(M,4)\), in questo caso il valore \(4\) è stato ipotizzato
1
2
# simulazione dalla posteriori
M_sim <- rnorm(1000, mean=parametri_posteriori$mu, sd=parametri_posteriori$sigma)
1
2
# simulazione dalla densità predittiva
y_sim <- rnorm(1000, mean=M_sim, sd=4)
1
2
# intervallo di credibilità previsto all'80%
round(quantile(y_sim, c(0.10, 0.90)), 1)

10%:11.8; 90%:22.6

L’intervallo di credibilità all’80% è più stretto dell’intervallo di credibilità previsto, in quanto non si conosce il valore di \(M\) (inference) né il valore di \(y\vert M\) (sampling).

Bivariate Bayesian Testing

Inferenza Bayesiana

Siano \(p_W\) e \(p_M\) le proporzioni di donne e uomini positivi.

Test d’ipotesi

  • Ipotesi 1 \(p_W>p_M\)
  • Ipotesi 2 \(p_W=p_M\)

Distribuzione a priori (proporzioni)

In un approccio discreto, un modello è una coppia \((p_W,p_M)\)
Ipotizzo una distribuzione discreta, con range tra \(0.1\) e \(0.9\) (quindi \(9\times 9\) possibili modelli).
La distribuzione è descrive la relazione tra le due proporzioni

  • \(P(p_W=p_M)=0.5\) (diagonale)
  • \(P(p_W\neq p_M)=0.5\) (fuori la diagonale)
1
2
3
# distribuzione test-priori
prior <- testing_prior(lo=0.1, hi=0.9, n_values=9, pequal=0.5)
round(prior, 3)
A matrix: 9 × 9 of type dbl
0.10.20.30.40.50.60.70.80.9
0.10.0560.0070.0070.0070.0070.0070.0070.0070.007
0.20.0070.0560.0070.0070.0070.0070.0070.0070.007
0.30.0070.0070.0560.0070.0070.0070.0070.0070.007
0.40.0070.0070.0070.0560.0070.0070.0070.0070.007
0.50.0070.0070.0070.0070.0560.0070.0070.0070.007
0.60.0070.0070.0070.0070.0070.0560.0070.0070.007
0.70.0070.0070.0070.0070.0070.0070.0560.0070.007
0.80.0070.0070.0070.0070.0070.0070.0070.0560.007
0.90.0070.0070.0070.0070.0070.0070.0070.0070.056
1
2
# plot della test-priori
draw_two_p(prior)

Verosimiglianza (Binomiale)

Si osservano 10 donne e 14 uomini positivi.
Si possono assumere campioni indipendenti e con distribuzione binomiale, quindi la verosimiglianza è il prodotto (vettoriale) delle densità binomiali

1
2
3
4
5
6
7
pW <- seq(0.1,0.9,by=0.1)
pM <- seq(0.1,0.9,by=0.1)
# outer è il prodotto tra vettore riga e colonna (nx1 * 1xn = nxn)
# a %*% t(b)
Likelihood <- outer(dbinom(10, size=20, prob=pW), 
  dbinom(14, size=20, prob=pM))
round(Likelihood,3)
A matrix: 9 × 9 of type dbl
0000.0000.0000.0000.0000.0000.000
0000.0000.0000.0000.0000.0000.000
0000.0000.0010.0040.0060.0030.000
0000.0010.0040.0150.0220.0130.001
0000.0010.0070.0220.0340.0190.002
0000.0010.0040.0150.0220.0130.001
0000.0000.0010.0040.0060.0030.000
0000.0000.0000.0000.0000.0000.000
0000.0000.0000.0000.0000.0000.000

Distribuzione a posteriori (proporzioni)

\(\mbox{Posteriori}=\frac{\mbox{Prori} \times \mbox{Verosimiglianza}}{\sum\big(\mbox{Prori} \times \mbox{Verosimiglianza}\big)}\)

1
2
3
# posterior <- prior*Likelihood/sum(prior*Likelihood)
posterior <- two_p_update(prior, c(10,10), c(14,6))
round(posterior,3)
A matrix: 9 × 9 of type dbl
0.10.20.30.40.50.60.70.80.9
0.10000.0000.0000.0000.0000.0000.000
0.20000.0000.0000.0010.0010.0010.000
0.30000.0000.0030.0090.0140.0080.001
0.40000.0110.0100.0350.0530.0300.002
0.50000.0020.1240.0520.0800.0460.004
0.60000.0010.0100.2770.0530.0300.002
0.70000.0000.0030.0090.1120.0080.001
0.80000.0000.0000.0010.0010.0040.000
0.90000.0000.0000.0000.0000.0000.000
1
2
# plot
draw_two_p(posterior)

Analisi delle differenze

Trasformo la matrice \(9\times 9\) in una matrice \(81\times 2\), ottengo le differenze tra \(p_W\) e \(p_M\), raggruppo per tale differenza sommando le probabilità (le due colonne hanno 9 valori, quindi 17 combinazioni).
Analizzo la distribuzione delle differenze tra le due proporzioni \(d=p_M-p_W\)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# differenze e probabilità

# tabella <- as.matrix(posterior)
# tabella <- data.frame(
#   diff21 = as.vector(outer(colnames(tabella), rownames(tabella), FUN=function(x,y) round(as.numeric(y)-as.numeric(x),1))),
#   Prob = as.vector(tabella)
# )

# d <- tabella %>%
#   group_by(diff21) %>%
#   summarise(Prob = sum(Prob), .groups = 'drop_last')

d <- two_p_summarize(posterior)
d %>% head() %>% round(3)
A tibble: 6 × 2
diff21Prob
<dbl><dbl>
-0.80.000
-0.70.000
-0.60.000
-0.50.000
-0.40.000
-0.30.001
1
2
# plot differenze
prob_plot(d)

Con la distribuzione a priori ho assunto che si ha il 50% di probabilità di ottenere proporzioni uguali (differenza nulla).
L’a posteriori mostra che la \(P(\mbox{d}=0)\) è elevata, ma è discreta la probabilità che la proporzione degli uomini sia maggiore rispetto quella delle donne.

1
2
# Posteriori: P(diff<0==p_W>p_M)
d %>% filter(diff21<0) %>% select(Prob) %>% sum() %>% round(3)

0.028

1
2
# Priori: P(diff<0==p_W>p_M)
sum(prior[upper.tri(prior)])

0.25

1
2
# Posteriori: P(diff=0==p_W=p_M)
d %>% filter(diff21==0) %>% select(Prob) %>% sum() %>% round(3)

0.528

1
2
# Priori: P(diff=0==p_W=p_M)
sum(diag(prior))

0.5

Distribuzione a priori (Beta)

Assumiamo che una curva beta rappresenti la conoscenza riguardo \(p_W\) e un’altra riguardo \(p_M\) e che siano indipendenti.
\(p_W \sim \mathrm{B}(1,1)\)
\(p_M \sim \mathrm{B}(1,1)\)

1
2
3
# genero dalla priori
df <- data.frame(pW=rbeta(1000,1,1), pM=rbeta(1000,1,1))
ggplot(df, aes(pW,pM)) + geom_point() + xlim(0,1) + ylim(0,1)

Verosimiglianza (Binomiale)

Si osservano 10 donne e 14 uomini positivi.
Si possono assumere campioni indipendenti e con distribuzione binomiale, quindi la verosimiglianza è il prodotto (vettoriale) delle densità binomiali

Distribuzione a posteriori (Beta)

Sarà una \(\mathrm{B}(p_W,p_M)\)

\(p_W \sim \mathrm{B}(10+1,10+1)\)
\(p_M \sim \mathrm{B}(14+1,6+1)\)

[TO DO] DA DETERMINARE ANALITICAMENTE L’A POSTERIORI

1
2
3
# simulo pW e pM
pW <- rbeta(1000, 11, 11)
pM <- rbeta(1000, 15, 7)
1
2
3
# plot posteriori
df <- data.frame(pW, pM)
ggplot(df, aes(pW,pM)) + geom_point() + xlim(0,1) + ylim(0,1)

1
2
# prob pW<pM
with(df, sum(pW<pM)/1000)

0.898

1
2
# differenza posteriori
df$d_21 <- with(df, pM-pW)
1
2
3
# plot differenze
ggplot(df, aes(d_21)) +
  geom_histogram(color="black", fill="red", bins=30)

1
2
# intervallo di credibilità per d
quantile(df$d_21, c(0.05, 0.95))

5%:-0.0468267513603719; 95%:0.410351553897697

\(P(-0.05<p_M-p_W<0.41)=0.9\)
Dal momento che gli interavalli contengono lo zero, non c’è evidenza significativa per dire che le proporzioni sono differenti.

1
2
# clear environment
rm(list=ls())

Normal model inference (\(\sigma\) sconosciuto)

Sia \(y\) una v.a. che modella i secondi necessari per calciare un rigore.
Prima abbiamo fatto inferenza su \(M\) campionando un modello normale, assumendo una deviazione standard \(S\), adesso entrambi parametri sono sconosciuti.

Distribuzione a priori (non-informativa)

Sia \(M\) che \(S\) sono continue, usiamo una priori “non-informativa”.
\(g(M,S)=\frac{1}{S}\)

Verosimiglianza

1
2
3
4
5
6
# observed data
df <- data.frame(Player="One",
                Time_to_Serve = c(20.9, 17.8, 14.9, 12.0, 14.1,
                                 22.8, 14.6, 15.3, 21.2, 20.7,
                                 12.2, 16.2, 15.6, 19.4, 22.3,
                                 14.1, 18.1, 23.6, 11.0, 17.3))
1
2
# verosimiglianza
# Likelihood <- prod(dnorm(Time_to_Serve, mean=M, sd=S))

[TO DO] NON COMPRENDO L’UTILITÀ DELLA FORMULA PRECEDENTE

1
# prod(dnorm(df$Time_to_Serve, mean=mean(df$Time_to_Serve), sd=sd(df$Time_to_Serve))) # ha senso?

1.92001903740555e-24

Distribuzione a posteriori (modello lineare)

\(Posteriori \propto Verosimiglianza \times \frac{1}{S}\)
Simulo \((M, S)\) dalla posteriori a 2 parametri.

Questo modello normale si può vedere come un modello lineare con solo l’intercetta.
[TO DO] DA CAPIRE LA RELAZIONE

1
2
3
# lm intercetta
fit <- lm(Time_to_Serve~1, data=df)
summary(fit)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Call:
lm(formula = Time_to_Serve ~ 1, data = df)

Residuals:
   Min     1Q Median     3Q    Max 
-6.205 -2.730 -0.455  3.545  6.395 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   17.205      0.851   20.22 2.62e-14 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 3.806 on 19 degrees of freedom

Similiamo da una a posteriori di \((M,S)\) usando una priori non informativa

1
2
# simuliamo da questo modello bayesiano
sim_fit <- arm::sim(fit, n.sims=1000)
1
2
3
# estraggo i vettori simulati di M e S
sim_M <- coef(sim_fit)
sim_S <- arm::sigma.hat(sim_fit)
1
2
# distribuzione a posteriori congiunta di M e S
ggplot(data.frame(sim_M, sim_S), aes(sim_M, sim_S)) + geom_point()

1
2
3
4
5
# andamento deviazione standard
ggplot(data.frame(sim_S), aes(sim_S)) + geom_density()

# intervallo di crdeibilità al 90%
round(quantile(sim_S, c(0.05, 0.95)),3)

5%:3.093; 95%:5.313

Regressione Bayesiana

Sia \(y\) la variabile dipendente che rappresenta i secondi necessari per calciare un rigore.
Sia \(X\) la variabile indipendente che definisce il giocatore che calcia (Player One e Player Two).
Obiettivo: quanto è più lento il player 2 rispetto l’1?

Regression framework \(y\sim\mathscr{N}\big(\beta_0+\beta_1\cdot I(\mbox{Player}=\mbox{Two}),S\big)\)

Distribuzione a priori (non-informativa)

\((\beta_0,\beta_1,S)\sim\frac{1}{S}\)

Verosimiglianza

1
2
3
4
5
6
7
8
9
10
11
12
# observed data
One <- data.frame(Player="One",
                Time_to_Serve = c(20.9, 17.8, 14.9, 12.0, 14.1,
                                 22.8, 14.6, 15.3, 21.2, 20.7,
                                 12.2, 16.2, 15.6, 19.4, 22.3,
                                 14.1, 18.1, 23.6, 11.0, 17.3))
Two <- data.frame(Player="Two",
                Time_to_Serve = c(20.5, 25.1, 21.4, 25.6, 41.2,
                                 23.9, 22.6, 19.0, 29.7, 36.4,
                                 18.4, 20.3, 26.9, 28.9, 22.9,
                                 31.5, 39.6, 29.4, 26.9, 24.5))
df <- rbind(One, Two)
1
2
# verosimiglianza
# Likelihood <- prod(dnorm(Time_to_Serve, mean=beta0+beta1*I(Player2), sd=S))

[TO DO] NON COMPRENDO L’UTILITÀ DELLA FORMULA PRECEDENTE

Distribuzione a posteriori (modello lineare)

\(Posteriori\propto \mbox{Verosimiglianza}\times \frac{1}{S}\)

Questo modello normale si può vedere come un modello lineare.
[TO DO] DA CAPIRE LA RELAZIONE

1
2
3
# stima del modello
fit <- lm(Time_to_Serve ~ Player, data=df)
fit
1
2
3
4
5
6
Call:
lm(formula = Time_to_Serve ~ Player, data = df)

Coefficients:
(Intercept)    PlayerTwo  
      17.20         9.53  

In media il giocatore 1 impiega \(17.20\) secondi, mentre il giocatore 2 impiega \(17.20+9.53\) secondi.

1
2
3
4
# generare dalla distribuzione a posteriori dei beta e sigma
sim_fit <- arm::sim(fit, n.sims=1000)
sim_beta <- coef(sim_fit)
sim_S <- arm::sigma.hat(sim_fit)
1
2
3
4
5
6
# plot posteriori congiunta dei beta
sim_beta <- data.frame(sim_beta)
names(sim_beta)[1] <- "Intercetta"
ggplot(sim_beta, aes(Intercetta, PlayerTwo)) + geom_point() + 
  xlab(expression(beta[0])) + ylab(expression(beta[1])) + 
  theme(axis.title.y = element_text(angle = 0, vjust = 0.5), axis.title=element_text(size=24))

1
2
# plot posteriori marginale di beta1
ggplot(sim_beta, aes(PlayerTwo)) + geom_density()

Il confronto diretto delle due distribuzioni marginali non è sensato, perché viene influenzato dalla differente variabilità delle due stime, quindi, è necessario standardizzarlo.

Standardized effect

\(h(\beta_1,S)=\frac{\beta_1}{S}\)
con \(\beta_1\) parametro di regressione e \(S\) deviazione standard.
Effetto standardizzato: il tempo medio che il giocatore due è più lento del giocatore uno, misurato in unità di deviazioni standard.

1
2
3
4
5
# plot posteriori marginale di beta1 standardizzato
posterior <- data.frame(sim_beta, sim_S)
standardized_effect <- with(posterior, PlayerTwo / sim_S)
ggplot(posterior, aes(standardized_effect)) + geom_density() + 
  xlab(expression(frac(beta[1],S)))

1
2
3
# intervallo di credibilità al 90% per l'effetto standardizzato
round(quantile(data.frame(sim_beta)$PlayerTwo / sim_S, c(0.05, 0.95)),3)

5%:1.151; 95%:2.423

La probabilità che l’effetto standardizzato di \(\beta_1\) sia tra 1.2 e 2.4 è il 90%