Immagina di aver appena concluso un test A/B su due versioni di una landing page. La versione B ha un tasso di conversione leggermente più alto.
Oppure, stai analizzando i dati di un esperimento e il gruppo trattato con un nuovo farmaco mostra una pressione sanguigna media inferiore. La domanda è sempre la stessa: questa differenza è reale o è solo frutto del caso?
Entrare nel mondo dei test di ipotesi può sembrare come aprire una cassetta degli attrezzi con decine di chiavi quasi identiche.
C’è il classico t-test di Student, il suo cugino più robusto, il test di Welch, e tutta una serie di alternative “non parametriche” per i casi difficili. Quale usare? E perché?
Welch e gli altri…
Una mappa pratica per orientarsi tra test t e alternative non parametriche
Ci sono momenti, in statistica, in cui la domanda sembra semplice: le medie di due gruppi sono diverse?
Poi ci si accorge che la risposta è un labirinto di varianti, ipotesi e test. C’è il t di Student classico, c’è il t di Welch, ci sono alternative non parametriche. E per ogni situazione – gruppi indipendenti, misure accoppiate, più di due campioni – serve la bussola giusta.
In questo articolo proviamo a costruire una mappa sintetica ma completa: non un manuale accademico, ma una guida operativa per capire quando usare Welch e quando scegliere altro.
1. Due gruppi indipendenti: il terreno di Welch
È lo scenario più comune: due gruppi distinti, ad esempio la pressione sanguigna nei maschi vs femmine, o la risposta a un farmaco tra gruppo A e gruppo B.
Ipotesi da verificare:
[math]H_0: \mu_1 = \mu_2[/math]
Le opzioni sul tavolo:
- t di Student (pooled): funziona se i due gruppi hanno varianze simili.
- t di Welch: valido anche con varianze diverse, è il default in R (
t.test(..., var.equal=FALSE)) e in Python (scipy.stats.ttest_ind(..., equal_var=False)). - Mann–Whitney U: alternativa non parametrica, utile se i dati sono ordinali o molto lontani dalla normalità.
👉 Regola pratica: se i campioni sono indipendenti e la variabilità non è uguale, usa Welch. Se le varianze sembrano simili, entrambi i test vanno bene, ma Welch non ti costa nulla.
2. Due campioni dipendenti: prima e dopo
Qui non si tratta più di due gruppi distinti, ma dello stesso soggetto misurato in condizioni diverse (es. “prima” e “dopo” un trattamento).
Ipotesi:
[math]H_0: \text{media delle differenze} = 0[/math]
Le opzioni:
- t accoppiato: se le differenze seguono (circa) una distribuzione normale.
- Wilcoxon signed-rank: se le differenze sono lontane dalla normalità o se i dati sono ordinali.
👉 Nota operativa: spesso il Wilcoxon ha più potenza del t quando le distribuzioni sono fortemente asimmetriche.
3. Un campione vs valore noto
Vuoi confrontare la media di un gruppo con un valore di riferimento (es. pressione media vs 120 mmHg).
- One-sample t: valido se il campione è normale.
- Wilcoxon signed-rank o test del segno: alternative non parametriche se la normalità è dubbia.
4. Più di due gruppi
Quando i gruppi diventano tre o più, non basta più il test t.
- ANOVA a una via: se le varianze sono omogenee.
- Welch’s ANOVA: se le varianze sono eterogenee.
- Kruskal–Wallis: alternativa non parametrica, utile con dati ordinali o distribuzioni problematiche.
- Misure ripetute: servono ANOVA per misure ripetute o modelli misti.
5. Perché Welch è diventato lo “standard moderno”
Storicamente il test t “pooled” era l’opzione principale. Oggi, però, Welch è preferito quasi ovunque. Perché?
- Robustezza: controlla meglio il livello di significatività anche con varianze molto diverse.
- Potenza: è uguale o superiore a quella del t classico.
- Praticità: elimina il fastidioso “doppio test” (prima verificare omoscedasticità, poi decidere il t).
- Neutralità: anche quando le varianze sono uguali, non perde praticamente nulla.
👉 Tradotto: se hai due campioni indipendenti, la prima scelta oggi è Welch.
6. Checklist operativa (flow-chart testuale)
Uno o due campioni?
- Uno → one-sample t o Wilcoxon.
- Due → vai al punto 2.
Indipendenti o accoppiati?
- Accoppiati → paired t o Wilcoxon.
- Indipendenti → vai al punto 3.
Tipo di variabile:
- Quantitativa continua → prosegui.
- Ordinale/Likert → Mann–Whitney.
Normalità:
- Se n è grande (≥30–40), i test t sono robusti.
- Se n è piccolo e distribuzione sospetta → non parametrico.
Varianze (solo se indipendenti):
- Simili → t Student o Welch.
- Diverse → Welch.
7. Esempio numerico
Gruppo A: 8, 9, 10, 11, 12 → varianza [math]s^2 = 2,5[/math]
Gruppo B: 20, 22, 24, 26, 28 → varianza [math]s^2 = 10[/math]
Test di Levene: [math]p = 0,02[/math]
[math]p = 0,02 \to \text{varianze diverse.}[/math]
t di Welch:
[math]\displaystyle t = -9,18, \, gl \approx 5,7, \, p < 0,001.[/math]
t di Student (pooled):
stesso valore di [math]t[/math], ma con [math]gl = 8[/math]. L’errore di tipo I reale, però, sale a ~0,08 invece di 0,05.
👉 Morale: Welch ti protegge dal falso positivo.
Approfondimento sui test: teoria ed esempi pratici
1. t di Student (pooled)
- Ipotesi: [math]H_0: \mu_1 = \mu_2[/math]
- Assunzioni:
- Campioni indipendenti
- Varianze uguali
- Dati circa normali
- Formula: [math]\displaystyle t = \frac{\bar{x}_1 – \bar{x}_2}{s_p \sqrt{\frac{1}{n_1} + \frac{1}{n_2}}} \quad\text{con}\quad s_p^2 = \frac{(n_1-1)s_1^2 + (n_2-1)s_2^2}{n_1+n_2-2}[/math]
- Esempio pratico: Supponiamo di confrontare l’altezza media di 20 maschi e 20 femmine. Se le varianze sono simili (test di Levene non significativo), il t pooled è appropriato.
2. t di Welch
- Ipotesi: [math]H_0: \mu_1 = \mu_2[/math]
- Assunzioni:
- Campioni indipendenti
- Non richiede varianze uguali
- Dati circa normali
- Formula (semplificata): [math]t = \frac{\bar{x}_1 – \bar{x}_2}{\sqrt{\frac{s_1^2}{n_1} + \frac{s_2^2}{n_2}}}[/math] I gradi di libertà sono stimati con la formula di Welch–Satterthwaite.
- Esempio pratico: Farmaco A ([math]n=12[/math], varianza=[math]5[/math]), Farmaco B ([math]n=15[/math], varianza=[math]20[/math]). Le varianze sono diverse → si usa Welch. Risultato: più affidabile, evita falsi positivi.
3. Mann–Whitney U
- Ipotesi: le distribuzioni dei due gruppi sono identiche (spesso interpretato come “mediane uguali”).
- Assunzioni:
- Campioni indipendenti
- Dati ordinali o non normali
- Idea del test: confronta i ranghi combinati, non le medie.
- Esempio pratico: Soddisfazione su scala Likert (1–5) tra due gruppi di clienti. Non ha senso fare una media aritmetica, quindi si usa Mann–Whitney.
4. t accoppiato
- Ipotesi: [math]H_0: \mu_d = 0[/math], dove [math]d = x_{\text{prima}} – x_{\text{dopo}}[/math].
- Assunzioni:
- Differenze normalmente distribuite
- Formula: [math]t = \frac{\bar{d}}{s_d / \sqrt{n}}[/math]
- Esempio pratico: Misuro la pressione di 10 pazienti prima e dopo un farmaco. Se le differenze sono distribuite normalmente, applico il t accoppiato per testare l’efficacia.
5. Wilcoxon signed-rank
- Ipotesi: la mediana delle differenze = 0.
- Assunzioni:
- Campioni appaiati
- Non richiede normalità
- Idea del test: ordina le differenze in valore assoluto e assegna segni → confronta se i segni positivi e negativi sono bilanciati.
- Esempio pratico: Voto di gradimento di uno stesso gruppo prima e dopo un workshop (scala 1–10, distribuzione asimmetrica).
6. One-sample t
- Ipotesi: [math]H_0: \mu = \mu_0[/math].
- Assunzioni:
- Dati normali.
- Formula: [math]t = \frac{\bar{x} – \mu_0}{s/\sqrt{n}}[/math]
- Esempio pratico: Campione di 30 studenti, altezza media = 172 cm. Confronto con valore noto 170 cm.
7. Test del segno
- Ipotesi: la mediana delle differenze = 0.
- Assunzioni:
- Dati appaiati
- Non richiede normalità
- Idea del test: conta quante differenze sono positive vs negative.
- Esempio pratico: Confronto “prima/dopo” sul tempo impiegato a completare un compito, con distribuzione estremamente asimmetrica.
8. ANOVA e varianti
- ANOVA classica: più di due gruppi, varianze uguali.
- Welch’s ANOVA: più di due gruppi, varianze diverse.
- Kruskal–Wallis: non parametrico, confronta ranghi.
- Esempio pratico: Confronto diete A, B, C.
- Se i dati sono normali e omoschedastici → ANOVA.
- Se varianze diverse → Welch’s ANOVA.
- Se distribuzione non normale → Kruskal–Wallis.
🐍 Una diagnostica automatica per scegliere il test statistico
Finora abbiamo costruito una checklist logica e un diagramma decisionale per capire quando usare il t-test di Welch o le sue alternative.
Ma nella pratica, quando abbiamo i dati in un file o in un DataFrame, può essere utile avere uno strumento automatico che ci guidi nella scelta del test.
Obiettivi dello snippet
Lo snippet Python che segue ha tre scopi principali:
-
Automatizzare la diagnosi – dato un dataset, il programma controlla:
-
numero di campioni,
-
indipendenza o appaiamento,
-
normalità delle distribuzioni,
-
omogeneità delle varianze.
-
-
Suggerire il test corretto – restituisce la raccomandazione su quale test statistico applicare:
-
t di Student, t di Welch, Wilcoxon, Mann–Whitney U, ANOVA, Kruskal–Wallis, ecc.
-
-
Fornire un output leggibile – il risultato non è un semplice “vero/falso”, ma una mini–diagnosi in linguaggio naturale, utile per studenti, data analyst e ricercatori.
Creiamo il dataset fittizio:
import pandas as pd
import numpy as np
np.random.seed(42)
# 1. Un campione (pressione sanguigna rispetto a 120)
pressione = np.random.normal(122, 5, 30)
# 2. Due campioni indipendenti (colesterolo maschi vs femmine)
maschi = np.random.normal(200, 15, 25)
femmine = np.random.normal(190, 12, 22)
# 3. Due campioni appaiati (prima e dopo dieta sugli stessi soggetti)
prima_dieta = np.random.normal(85, 8, 20)
dopo_dieta = prima_dieta - np.random.normal(5, 3, 20) # effetto medio -5 kg
# 4. Tre campioni indipendenti (3 tipi di dieta e perdita di peso)
dieta_A = np.random.normal(4, 1, 15)
dieta_B = np.random.normal(6, 1.2, 15)
dieta_C = np.random.normal(5, 0.8, 15)
# Find the maximum length among all arrays
max_len = max(len(pressione), len(maschi), len(femmine), len(prima_dieta), len(dopo_dieta), len(dieta_A), len(dieta_B), len(dieta_C))
# Pad shorter arrays with NaN to match the maximum length
def pad_array(arr, length):
return np.pad(arr.astype(float), (0, length - len(arr)), 'constant', constant_values=np.nan)
pressione_padded = pad_array(pressione, max_len)
maschi_padded = pad_array(maschi, max_len)
femmine_padded = pad_array(femmine, max_len)
prima_dieta_padded = pad_array(prima_dieta, max_len)
dopo_dieta_padded = pad_array(dopo_dieta, max_len)
dieta_A_padded = pad_array(dieta_A, max_len)
dieta_B_padded = pad_array(dieta_B, max_len)
dieta_C_padded = pad_array(dieta_C, max_len)
# Creazione DataFrame
df = pd.DataFrame({
"pressione": pressione_padded,
"colesterolo_maschi": maschi_padded,
"colesterolo_femmine": femmine_padded,
"peso_prima_dieta": prima_dieta_padded,
"peso_dopo_dieta": dopo_dieta_padded,
"dieta_A": dieta_A_padded,
"dieta_B": dieta_B_padded,
"dieta_C": dieta_C_padded
})
df.head()
Come usare il dataset
Il dataset è strutturato in modo da coprire i casi più comuni, dal confronto di un singolo campione con un valore noto fino all’analisi di più di due gruppi. L’obiettivo è farti capire che a ogni scenario corrisponde un test specifico.
Mappatura dei test statistici
Ecco una mappa dettagliata che collega ogni colonna del tuo dataset al test statistico appropriato e all’ipotesi che puoi verificare.
1. Test a un campione
- Colonna:
pressione - Scenario: Confrontare la pressione media del campione con un valore di riferimento (nell’esempio,
120 mmHg). - Ipotesi principale: L’ipotesi nulla () è che la media della pressione del campione sia uguale a 120 mmHg ().
- Test da usare: Usa il test t a un campione se i dati sono distribuiti normalmente. Se la distribuzione è molto diversa dalla normalità, puoi ricorrere al test di Wilcoxon (se la mediana è un indicatore più appropriato) o al test del segno.
2. Test tra due gruppi indipendenti
- Colonne:
colesterolo_maschiecolesterolo_femmine - Scenario: Confrontare le medie di due gruppi indipendenti, in questo caso, il colesterolo nei maschi e nelle femmine.
- Ipotesi principale: L’ipotesi nulla () è che la media del colesterolo nei maschi sia uguale a quella delle femmine ().
- Test da usare: Se le varianze dei due gruppi sono simili (puoi verificarlo con un test di Levene), puoi usare il t di Student. Se le varianze sono diverse, come spesso accade, la scelta migliore e più robusta è il t di Welch. Se i dati non sono normali, l’alternativa non parametrica è il test di Mann-Whitney U.
3. Test tra due campioni appaiati
- Colonne:
peso_prima_dietaepeso_dopo_dieta - Scenario: Misurare un cambiamento nello stesso gruppo di individui, per esempio il peso prima e dopo una dieta.
- Ipotesi principale: L’ipotesi nulla () è che la media delle differenze tra il peso iniziale e quello finale sia zero ().
- Test da usare: Se le differenze tra le misurazioni sono distribuite normalmente, usa il t-test accoppiato. In caso contrario, l’alternativa non parametrica è il test dei ranghi con segno di Wilcoxon.
4. Test tra più di due gruppi
- Colonne:
dieta_A,dieta_Bedieta_C - Scenario: Confrontare le medie di tre o più gruppi, come l’effetto di diverse diete sul peso.
- Ipotesi principale: L’ipotesi nulla () è che le medie dei tre gruppi siano tutte uguali ().
- Test da usare: Se i dati sono normali e le varianze omogenee, l’opzione è l’ANOVA a una via. Se le varianze sono diverse, come suggerito dal tuo testo, si usa la Welch ANOVA. Se la distribuzione dei dati non è normale, usa l’equivalente non parametrico, il test di Kruskal-Wallis.
Lo snippet “diagnostico”:
import numpy as np
import pandas as pd
from scipy import stats
# =============================
# Dataset fittizio (pressione sanguigna)
# =============================
np.random.seed(42)
# Gruppo A (maschi, sd più alta)
group_A = np.random.normal(loc=125, scale=12, size=30)
# Gruppo B (femmine, sd più bassa)
group_B = np.random.normal(loc=120, scale=8, size=28)
df = pd.DataFrame({
"valore": np.concatenate([group_A, group_B]),
"gruppo": ["A"]*len(group_A) + ["B"]*len(group_B)
})
# =============================
# Funzione diagnostica
# =============================
def diagnostica_test(df, valore_col="valore", gruppo_col="gruppo", paired=False):
"""
Determina quale test statistico usare per confrontare gruppi.
"""
gruppi = [g[valore_col].values for _, g in df.groupby(gruppo_col)]
if len(gruppi) == 1:
# Caso: un solo campione vs valore noto
x = gruppi[0]
shapiro_p = stats.shapiro(x).pvalue
if shapiro_p > 0.05:
return "One-sample t-test (dati ~ normali)"
else:
return "Test non parametrico (Wilcoxon o test del segno)"
elif len(gruppi) == 2:
x, y = gruppi
if paired:
# Caso: dati appaiati
diff = x[:min(len(x), len(y))] - y[:min(len(x), len(y))]
shapiro_p = stats.shapiro(diff).pvalue
if shapiro_p > 0.05:
return "Paired t-test (differenze ~ normali)"
else:
return "Wilcoxon signed-rank test (differenze non normali)"
else:
# Caso: due gruppi indipendenti
shapiro_x = stats.shapiro(x).pvalue
shapiro_y = stats.shapiro(y).pvalue
normali = (shapiro_x > 0.05) and (shapiro_y > 0.05)
levene_p = stats.levene(x, y).pvalue
var_equal = levene_p > 0.05
if normali:
if var_equal:
return "t-test di Student (varianze simili)"
else:
return "t-test di Welch (varianze diverse)"
else:
return "Mann-Whitney U test (non parametrico)"
else:
# Caso: più di due gruppi
norm_p = [stats.shapiro(g).pvalue for g in gruppi]
normali = all(p > 0.05 for p in norm_p)
levene_p = stats.levene(*gruppi).pvalue
var_equal = levene_p > 0.05
if normali:
if var_equal:
return "ANOVA one-way (varianze simili)"
else:
return "Welch ANOVA (varianze diverse)"
else:
return "Kruskal-Wallis test (non parametrico)"
# =============================
# ESEMPIO DIAGNOSTICA
# =============================
risultato = diagnostica_test(df, valore_col="valore", gruppo_col="gruppo", paired=False)
print("Diagnosi statistica:", risultato)
🔎 Output atteso (con il nostro dataset)
Per far scattare la raccomandazione “t-test di Welch”, basterebbe aumentare la differenza tra le deviazioni standard nel codice di generazione dati (es.
scale=15vsscale=5).
8. Una frase per ricordare tutto
Se devi confrontare le medie di due gruppi indipendenti, scegli Welch: funziona con varianze uguali o diverse, è robusto, non richiede pre-test. Riserva il t di Student pooled solo a casi in cui sei sicuro di avere varianze identiche e vuoi spremere un briciolo di potenza in più. Se la normalità crolla, passa a un test non parametrico.




