import arviz as az
import bambi as bmb
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
import pingouin as pg
import statistics as st
import warnings
"ignore") warnings.filterwarnings(
74 Confronto tra le medie di due gruppi
Prerequisiti
Concetti e competenze chiave
Preparazione del Notebook
int = sum(map(ord, "regr_two_groups"))
seed: = np.random.default_rng(seed=seed)
rng: np.random.Generator ="colorblind")
sns.set_theme(palette"arviz-darkgrid")
az.style.use(%config InlineBackend.figure_format = "retina"
Introduzione
Nel Capitolo 60, abbiamo discusso l’inferenza sulla differenza tra le medie di due campioni indipendenti utilizzando un approccio bayesiano. In quell’analisi, i due gruppi sono stati considerati entità distinte e abbiamo calcolato la differenza tra le loro medie.
Un’alternativa consiste nell’uso di un modello di regressione. In questo caso, invece di calcolare direttamente la differenza tra le medie, si introduce una variabile indicatrice (“dummy”) nel modello di regressione. La variabile indicatrice codifica l’appartenenza ai gruppi con valori binari: 0 per il gruppo di riferimento e 1 per il gruppo di confronto:
\[ x_i = \begin{cases} 0 & \text{se l'osservazione } i \text{ è nel gruppo 0} \\ 1 & \text{se l'osservazione } i \text{ è nel gruppo 1} \end{cases} \]
Il modello di regressione stima un coefficiente per la variabile indicatrice, che rappresenta la differenza tra le medie dei due gruppi. In questo modo, la variabile “dummy” funge da indicatore del gruppo, permettendo di stimare in modo efficiente la differenza tra le medie.
Entrambi i metodi sono validi per analizzare la differenza tra le medie di due gruppi indipendenti; tuttavia, il modello di regressione offre maggiore flessibilità e potenzialità di espansione. Questo modello permette di includere ulteriori variabili esplicative, ampliando la nostra capacità di comprendere i fattori che influenzano il risultato d’interesse. Tale versatilità è particolarmente vantaggiosa per esaminare come altre variabili possano influire sulla differenza tra le medie o per analizzare più variabili contemporaneamente.
74.1 Regressione bayesiana per due gruppi indipendenti
Nel contesto bayesiano, il modello di regressione può essere formulato nel modo seguente:
\[ \begin{align*} y_i & \sim \mathcal{N}(\mu_i, \sigma), \\ \mu_i & = \alpha + \beta x_i. \end{align*} \]
In questa rappresentazione:
- \(\alpha\) agisce come intercetta,
- \(\beta\) è il coefficiente angolare o la pendenza,
- \(\sigma\) è l’errore standard associato alle osservazioni.
Nel caso specifico, la variabile \(x\) è una variabile indicatrice che assume i valori 0 o 1. Per il gruppo identificato da \(x = 0\), il modello si riduce a:
\[ \begin{align*} y_i & \sim \mathcal{N}(\mu_i, \sigma), \\ \mu_i & = \alpha. \end{align*} \]
Questo implica che \(\alpha\) rappresenta la media del gruppo codificato come \(x = 0\).
Per il gruppo contrassegnato da \(x = 1\), il modello diventa:
\[ \begin{align*} y_i & \sim \mathcal{N}(\mu_i, \sigma), \\ \mu_i & = \alpha + \beta. \end{align*} \]
In termini dei parametri del modello, la media per il gruppo codificato con \(x = 1\) è rappresentata da \(\alpha + \beta\). In questa configurazione, \(\beta\) indica la differenza tra la media del gruppo con $ x = 1 $ e quella del gruppo con \(x = 0\). Di conseguenza, l’analisi della differenza tra le medie dei due gruppi può essere effettuata attraverso l’inferenza sul parametro \(\beta\). In sintesi, per confrontare le medie dei due gruppi indipendenti, si può esaminare la distribuzione a posteriori di \(\beta\).
74.2 Un esempio illustrativo
Esaminiamo nuovamente i dati relativi al quoziente di intelligenza dei bambini le cui madri hanno completato oppure no la scuola superiore. Ci poniamo il problema di replicare i risultati ottenuti in precedenza usando l’analisi di regressione.
Leggiamo i dati:
= pd.read_stata("../../data/kidiq.dta")
kidiq kidiq.head()
kid_score | mom_hs | mom_iq | mom_work | mom_age | |
---|---|---|---|---|---|
0 | 65 | 1.0 | 121.117529 | 4 | 27 |
1 | 98 | 1.0 | 89.361882 | 4 | 25 |
2 | 85 | 1.0 | 115.443165 | 4 | 27 |
3 | 83 | 1.0 | 99.449639 | 3 | 25 |
4 | 115 | 1.0 | 92.745710 | 4 | 27 |
"mom_hs"]).size() kidiq.groupby([
mom_hs
0.0 93
1.0 341
dtype: int64
Ci sono 93 bambini la cui madre non ha completato le superiori e 341 bambini la cui madre ha ottenuto il diploma di scuola superiore.
= [st.mean, st.stdev]
summary_stats "mom_hs"]).aggregate(summary_stats) kidiq.groupby([
kid_score | mom_iq | mom_work | mom_age | |||||
---|---|---|---|---|---|---|---|---|
mean | stdev | mean | stdev | mean | stdev | mean | stdev | |
mom_hs | ||||||||
0.0 | 77.548387 | 22.573800 | 91.889152 | 12.630498 | 2.322581 | 1.226175 | 21.677419 | 2.727323 |
1.0 | 89.319648 | 19.049483 | 102.212049 | 14.848414 | 3.052786 | 1.120727 | 23.087977 | 2.617453 |
az.plot_violin(
{"mom_hs=0": kidiq.loc[kidiq.mom_hs == 0, "kid_score"],
"mom_hs=1": kidiq.loc[kidiq.mom_hs == 1, "kid_score"],
}; )
Iniziamo l’inferenza statistica sulla differenza tra le medie dei due gruppi utilizzando bambi
. Questo pacchetto offre una sintassi semplice per formulare il modello bayesiano di interesse. Un altro vantaggio è che bambi
selezionerà automaticamente le distribuzioni a priori appropriate per i parametri del modello, rendendo il processo più intuitivo.
Il modello di regressione sopra descritto si scrive nel modo seguente.
= bmb.Model("kid_score ~ mom_hs", kidiq) mod
Effettuiamo il campionamento.
= mod.fit(nuts_sampler="numpyro", idata_kwargs={"log_likelihood": True}) results
Possiamo ispezionare le proprietà del modello nel modo seguente.
mod
Formula: kid_score ~ mom_hs
Family: gaussian
Link: mu = identity
Observations: 434
Priors:
target = mu
Common-level effects
Intercept ~ Normal(mu: 86.7972, sigma: 110.1032)
mom_hs ~ Normal(mu: 0.0, sigma: 124.2132)
Auxiliary parameters
sigma ~ HalfStudentT(nu: 4.0, sigma: 20.3872)
------
* To see a plot of the priors call the .plot_priors() method.
* To see a summary or plot of the posterior pass the object returned by .fit() to az.summary() or az.plot_trace()
Le distribuzioni a priori utilizzate di default dal modello possono essere visualizzate nel modo seguente.
= mod.plot_priors() _
Sampling: [Intercept, mom_hs, sigma]
Per ispezionare il nostro posteriore e il processo di campionamento possiamo utilizzare az.plot_trace()
. L’opzione kind='rank_vlines'
ci fornisce una variante del grafico di rango che utilizza linee e punti e ci aiuta a ispezionare la stazionarietà delle catene. Poiché non c’è un modello chiaro o deviazioni serie dalle linee orizzontali, possiamo concludere che le catene sono stazionarie.
= az.plot_trace(results) _
=2) az.summary(results, round_to
mean | sd | hdi_3% | hdi_97% | mcse_mean | mcse_sd | ess_bulk | ess_tail | r_hat | |
---|---|---|---|---|---|---|---|---|---|
Intercept | 77.55 | 2.01 | 73.68 | 81.27 | 0.03 | 0.02 | 4272.34 | 2738.90 | 1.0 |
mom_hs | 11.76 | 2.25 | 7.74 | 16.17 | 0.03 | 0.03 | 4169.77 | 2921.90 | 1.0 |
sigma | 19.88 | 0.66 | 18.69 | 21.12 | 0.01 | 0.01 | 4540.09 | 3039.19 | 1.0 |
Il parametro “Intercept” rappresenta la stima a posteriori del punteggio del QI per il gruppo codificato con “mom_hs” uguale a 0. La media a posteriori di questo gruppo è di 77.6, che è praticamente identica al valore campionario corrispondente.
Il parametro “mom_hs” corrisponde alla stima a posteriori della differenza nei punteggi del QI tra il gruppo codificato con “mom_hs” uguale a 1 e il gruppo codificato con “mom_hs” uguale a 0. Anche in questo caso, la differenza a posteriori di 11.8 tra le medie dei due gruppi è molto simile alla differenza campionaria tra le medie dei due gruppi. La parte importante della tabella riguarda l’intervallo di credibilità al 94%, che è [7.5, 16.2], e che non include lo 0. Ciò significa che, con un livello di certezza soggettiva del 94%, possiamo essere sicuri che il QI dei bambini le cui madri hanno il diploma superiore sarà maggiore (in media) di almeno 7.5 punti, e tale differenza può arrivare fino a 16.2 punti, rispetto al QI dei bambini le cui madri non hanno completato la scuola superiore.
Se confrontiamo questi risultati con quelli ottenuti nel capitolo {ref}two_groups_comparison_notebook
, notiamo che sono quasi identici. Le piccole differenze che si osservano possono essere attribuite sia all’approssimazione numerica sia al fatto che nel modello precedente abbiamo consentito deviazioni standard diverse per i due gruppi, mentre nel caso attuale abbiamo assumo la stessa variabilità per entrambi i gruppi.
Usiamo ora l’approccio di massima verosimiglianza.
= pg.linear_regression(kidiq["mom_hs"], kidiq["kid_score"])
lm round(2) lm.
names | coef | se | T | pval | r2 | adj_r2 | CI[2.5%] | CI[97.5%] | |
---|---|---|---|---|---|---|---|---|---|
0 | Intercept | 77.55 | 2.06 | 37.67 | 0.0 | 0.06 | 0.05 | 73.50 | 81.59 |
1 | mom_hs | 11.77 | 2.32 | 5.07 | 0.0 | 0.06 | 0.05 | 7.21 | 16.34 |
I risultati sono quasi identici a quelli trovati con l’approccio bayesiano.
Il test bayesiano di ipotesi può essere svolto, per esempio, calcolando la probabilità che \(\beta_{mean\_diff} > 0\). Questa probabilità è 1, per cui concludiamo che la media del gruppo codificato con “mom_hs = 1” è maggiore della media del gruppo codificato con “mom_hs = 0”.
="mom_hs", ref_val=0, figsize=(6, 3)); az.plot_posterior(results, var_names
Un valore numerico si ottiene nel modo seguente.
results.posterior
<xarray.Dataset> Size: 104kB Dimensions: (chain: 4, draw: 1000) Coordinates: * chain (chain) int64 32B 0 1 2 3 * draw (draw) int64 8kB 0 1 2 3 4 5 6 7 ... 993 994 995 996 997 998 999 Data variables: Intercept (chain, draw) float64 32kB 80.81 75.64 77.14 ... 77.32 77.43 mom_hs (chain, draw) float64 32kB 7.963 13.55 10.86 ... 9.91 10.79 12.88 sigma (chain, draw) float64 32kB 19.3 20.92 20.21 ... 19.26 19.12 20.3 Attributes: created_at: 2024-07-30T09:47:03.975197+00:00 arviz_version: 0.18.0 inference_library: numpyro inference_library_version: 0.15.1 sampling_time: 1.772095 tuning_steps: 1000 modeling_interface: bambi modeling_interface_version: 0.14.0
# Probabiliy that posterior is > 0
"mom_hs"] > 0).mean().item() (results.posterior[
1.0
74.3 Parametrizzazione alternativa
Consideriamo adesso il caso in cui, per distinguere i gruppi, anziché una variabile dicotomica, con valori 0 e 1, usiamo una variabile qualitativa con i nomi dei due gruppi. Introduciamo questa nuova variabile nel data frame.
# Add a new column 'hs' with the categories based on 'mom_hs'
"hs"] = kidiq["mom_hs"].map({0: "not_completed", 1: "completed"})
kidiq[ kidiq.tail()
kid_score | mom_hs | mom_iq | mom_work | mom_age | hs | |
---|---|---|---|---|---|---|
429 | 94 | 0.0 | 84.877412 | 4 | 21 | not_completed |
430 | 76 | 1.0 | 92.990392 | 4 | 23 | completed |
431 | 50 | 0.0 | 94.859708 | 2 | 24 | not_completed |
432 | 88 | 1.0 | 96.856624 | 2 | 21 | completed |
433 | 70 | 1.0 | 91.253336 | 2 | 25 | completed |
Adattiamo il modello ai dati, usando questa nuova variabile e forziamo a zero l’intercetta che Bambi aggiunge di default al modello.
= bmb.Model("kid_score ~ 0 + hs", kidiq)
mod_2 = mod_2.fit(nuts_sampler="numpyro", idata_kwargs={"log_likelihood": True}) results_2
Ispezionare il modello e le distribuzioni a priori.
mod_2
Formula: kid_score ~ 0 + hs
Family: gaussian
Link: mu = identity
Observations: 434
Priors:
target = mu
Common-level effects
hs ~ Normal(mu: [0. 0.], sigma: [124.2132 124.2132])
Auxiliary parameters
sigma ~ HalfStudentT(nu: 4.0, sigma: 20.3872)
------
* To see a plot of the priors call the .plot_priors() method.
* To see a summary or plot of the posterior pass the object returned by .fit() to az.summary() or az.plot_trace()
= mod_2.plot_priors() _
Sampling: [hs, sigma]
Esaminiamo le distribuzioni a posteriori dei parametri del modello.
= az.plot_trace(results_2) _
az.summary(results_2)
mean | sd | hdi_3% | hdi_97% | mcse_mean | mcse_sd | ess_bulk | ess_tail | r_hat | |
---|---|---|---|---|---|---|---|---|---|
hs[completed] | 89.297 | 1.089 | 87.209 | 91.231 | 0.016 | 0.012 | 4429.0 | 3149.0 | 1.0 |
hs[not_completed] | 77.506 | 1.988 | 73.744 | 81.191 | 0.031 | 0.022 | 4102.0 | 2940.0 | 1.0 |
sigma | 19.881 | 0.660 | 18.647 | 21.112 | 0.010 | 0.007 | 4216.0 | 2870.0 | 1.0 |
In questo caso, notiamo che abbiamo ottenuto le distribuzioni a posteriori per i parametri hs[completed]
e hs[not_completed]
che corrispondono alle medie dei due gruppi. Tali distribuzioni a posteriori illustrano direttamente l’incertezza sulla media dei due gruppi, alla luce della variabilità campionaria e delle nostre credenze a priori.
Possiamo svolgere il test bayesiano di ipotesi sulla differenza tra le due medie a posteriori nel modo seguente.
= results_2.posterior["hs"]
post_group = post_group.sel(hs_dim="completed") - post_group.sel(hs_dim="not_completed")
diff =0, figsize=(6, 3)); az.plot_posterior(diff, ref_val
# Probabiliy that posterior is > 0
> 0).mean().item() (post_group
1.0
Informazioni sull’Ambiente di Sviluppo
%load_ext watermark
%watermark -n -u -v -iv -w -m
Last updated: Tue Jul 30 2024
Python implementation: CPython
Python version : 3.12.4
IPython version : 8.26.0
Compiler : Clang 16.0.6
OS : Darwin
Release : 23.6.0
Machine : arm64
Processor : arm
CPU cores : 8
Architecture: 64bit
arviz : 0.18.0
seaborn : 0.13.2
matplotlib: 3.9.1
bambi : 0.14.0
numpy : 1.26.4
pandas : 2.2.2
pingouin : 0.5.4
Watermark: 2.4.3