Tutti ci siamo passati. All’università, o studiando per conto tuo, concetti come p-value, test t e ANOVA sembrano filare lisci. La teoria ha senso. Poi ti siedi davanti allo schermo, importi SciPy, passi i tuoi array a una funzione e Python ti sputa fuori una tupla di decimali infiniti.
A quel punto ti fermi e pensi:
“Ok, ma in soldoni questo numero mi sta dicendo che la nuova landing page funziona o no?”.
La verità è che conoscere la teoria non basta se non sai come tradurla nel codice di tutti i giorni.
Questo tutorial nasce per chiudere esattamente questo divario. Non ci limiteremo a fare un copia-incolla delle documentazioni ufficiali; prenderemo un caso reale, scriveremo il codice necessario e, soprattutto, vedremo come interpretare i numeri per evitare figuracce quando devi presentare i risultati.
Setup: cosa serve
Per iniziare, non hai bisogno di librerie complesse.
Useremo il pacchetto base della data science in Python, concentrandoci su SciPy, che rappresenta lo standard de facto per i test statistici:
import numpy as np import pandas as pd from scipy import stats
Facoltative ma utilissime:
import matplotlib.pyplot as plt import seaborn as sns
👉 useremo principalmente SciPy, che è lo standard per i test statistici in Python.
Caso reale: dati di esempio
Un caso reale: A/B Testing sui dati
Immagina questo scenario: hai appena lanciato una nuova versione (Versione B) della tua landing page e vuoi confrontarla con la vecchia (Versione A). La domanda di business che ti pone il tuo team è diretta: “La nuova versione migliora davvero le conversioni o il tempo di permanenza?”
Per rispondere, simuliamo i dati di due campioni numerici:
import numpy as np
np.random.seed(42) A = np.random.normal(loc=50, scale=10, size=100) B = np.random.normal(loc=55, scale=10, size=100)
1. Test t (confronto tra medie)
Il test t per campioni indipendenti è lo strumento corretto quando hai una variabile numerica, vuoi confrontare due gruppi distinti e i dati presentano una distribuzione approssimativamente normale.
Proviamo a lanciare il test di base fornito da SciPy:
Test t indipendente
t_stat, p_value = stats.ttest_ind(A, B) print(t_stat, p_value)
-4.7546959435052765 3.8191352626795345e-06
L’interpretazione rapida che tutti impariamo è quella di guardare il p-value: se è inferiore a 0.05, consideriamo la differenza statisticamente significativa. In questo caso, il valore è talmente vicino allo zero che non ci sono dubbi.
Tuttavia, fermarsi qui significa commettere un errore procedurale comune: stiamo dando per scontato che la varianza tra i due gruppi sia identica.
👉 Regola pratica:
if p_value < 0.05:
print("Differenza significativa")
else:
print("Nessuna evidenza di differenza")
Differenza significativa
La variante robusta: Il Test di Welch
Il test t classico (quello di Student) assume rigorosamente che i due gruppi abbiano la stessa varianza, ovvero la stessa “dispersione” dei dati.
Se questa ipotesi è falsa (e nel mondo reale lo è quasi sempre) il test può portarti a conclusioni sbagliate, sottostimando o sovrastimando la significatività della differenza.
Per tutelarsi, la scelta migliore è usare il Test di Welch, che indichiamo a Python aggiungendo semplicemente un parametro:
stats.ttest_ind(A, B, equal_var=False) Output: TtestResult(statistic=-4.754695943505277, pvalue=3.824684669406089e-06, df=197.52867431439725)
Cosa cambia con equal_var=False?
Scrivendo equal_var=False, diciamo all’algoritmo di non assumere che le varianze siano identiche.
Questo approccio adatta automaticamente i gradi di libertà ed è nettamente più affidabile nella pratica lavorativa, tanto da essere la scelta di default di molti data scientist esperti.
In sintesi: Perché è importante?
Il test t classico (Student) assume:
- stessa varianza nei due gruppi
- stessa “dispersione” dei dati
👉 Se questa ipotesi è falsa, il test può:
- sottostimare o sovrastimare la significatività
- portarti a conclusioni sbagliate
Il test di Welch ( quello che abbiamo usato)
È più robusto perché:
- non richiede varianze uguali
- adatta automaticamente i gradi di libertà
- è più affidabile nella pratica reale
Analisi completa dell’output
Ora che abbiamo lanciato il test corretto, analizziamo i tre valori restituiti dalla funzione per capire esattamente cosa stiamo leggendo.
statistic (-4.75):
Rappresenta la distanza standardizzata tra le due medie.
A livello concettuale, si calcola come:
[math]\displaystyle \begin{aligned} t = \frac{\bar{x}_1 – \bar{x}_2}{\text{errore standard}} \end{aligned}[/math]
Un valore alto in valore assoluto indica una differenza marcata tra i gruppi. Il segno negativo ci informa semplicemente che la media del gruppo A è inferiore a quella del gruppo B.
p-value (3.82e-06):
È la probabilità di osservare una differenza così estrema qualora le due medie fossero, nella realtà, perfettamente uguali ([math]H_0[/math]). Essendo un numero infinitesimale, possiamo scartare con sicurezza l’ipotesi che la differenza sia frutto del caso. Attenzione: un [math]p\text{-value}[/math] basso certifica che la differenza esiste, non che sia “enorme”.
df (197.53):
I gradi di libertà. Nel test classico questo valore è sempre un numero intero calcolato come [math]n_1 + n_2 – 2[/math]. Nel test di Welch, invece, i gradi di libertà vengono stimati con una formula più complessa che penalizza il risultato in base alle differenze di varianza, portando a valori decimali. Un numero alto (vicino a 200) indica che il test gode di un’ottima stabilità.
Interpretazione completa
Mettiamo tutto insieme:
- [math]t = -4.75[/math] → differenza forte
- [math]p\text{-value} \approx 0[/math] → evidenza schiacciante
- [math]df \approx 197[/math] → stima affidabile
Conclusione corretta
- 👉 I due gruppi hanno medie significativamente diverse
- 👉 La differenza NON è spiegabile con il caso
- 👉 Il gruppo B performa meglio di A
⚠️ Il pezzo mancante: la Dimensione dell’Effetto (Cohen’s d)
Molte analisi si fermano al p-value, ma in contesti aziendali questo è un errore grave.
La significatività statistica non coincide con l’importanza pratica.
Se hai milioni di visite sulla tua landing page, anche un miglioramento dello 0.001% risulterà statisticamente significativo, ma probabilmente non giustificherà i costi di implementazione della nuova pagina. Per capire quanto conta davvero la differenza, ci serve una metrica di impatto: il d di Cohen.
Ecco come calcolarlo in Python, ricordandoci di utilizzare la varianza campionaria (ddof=1):
mean_diff = np.mean(A) - np.mean(B) # Usiamo ddof=1 per ottenere la varianza campionaria pooled_std = np.sqrt((np.var(A, ddof=1) + np.var(B, ddof=1)) / 2) cohen_d = mean_diff / pooled_std print(cohen_d)
-0.67580305413896
Di default, NumPy calcola la varianza della popolazione (gradi di libertà = 0). Quando si lavora con campioni statistici per inferenza, si dovrebbe sempre usare la varianza campionaria, impostando il parametro
ddof=1(Delta Degrees of Freedom).
Come si interpreta il risultato?
Le linee guida standard suggeriscono che un valore assoluto di 0.2 rappresenta un effetto piccolo, 0.5 un effetto medio e 0.8 un effetto grande.
Nel nostro esempio, con un d pari a circa 0.67, non solo abbiamo la certezza statistica che i due gruppi si comportano in modo diverso, ma sappiamo anche che la Versione B della landing page genera un miglioramento di entità medio-grande nel mondo reale.
Abbiamo risposto alla domanda del team, con i numeri a supporto.
Quale test scegliere?
1. Il bivio della Normalità
La prima domanda è: i miei dati seguono una distribuzione normale (a campana)?
- SÌ: Passa ai test Parametrici (Test t).
- NO: Se i dati sono fortemente asimmetrici o il campione è molto piccolo ([math]n < 30[/math]), usa i test Non Parametrici (es. Mann-Whitney U-test).
2. Il bivio della Varianza (Omoschedasticità)
Se sei nel campo dei test parametrici, guarda la dispersione dei dati:
- Varianze Uguali: Puoi usare il Test t di Student classico.
- Varianze Diverse: Devi usare il Test di Welch (
equal_var=False).
Consiglio pro: Se hai dubbi, scegli sempre Welch. È più sicuro.
3. Il bivio del numero di gruppi
- 2 Gruppi: Test t o Mann-Whitney.
- [math]3+[/math] Gruppi: ANOVA o Kruskal-Wallis (che vedremo nella Parte 2).
Tabella di Consultazione Rapida
| Se i dati sono… | E vuoi confrontare… | Il test giusto è: | Funzione Python (SciPy) |
|---|---|---|---|
| Normali | 2 medie (varianze uguali) | Test t di Student |
|
| Normali | 2 medie (varianze diverse) | Test di Welch |
|
| Non Normali | 2 distribuzioni (mediane) | Mann-Whitney U |
|
| Normali | [math]3+[/math] medie | ANOVA (One-way) |
|
- Visualizza: Crea un istogramma o un boxplot. Se vedi outlier giganti o distribuzioni “strane”, la normalità è a rischio.
- Valida: Se vuoi essere matematicamente certo, lancia:
Se il [math]p\text{-value}[/math] è basso, i dati non sono normali. - Scegli:
- Tutto ok? [math]\rightarrow[/math]
- Dati sporchi? [math]\rightarrow[/math]
- Misura l’impatto: Non chiudere mai l’analisi senza il d di Cohen.
I 4 Errori che “rompono” il tuo Test
1. La trappola della Normalità (Outliers)
Il Test t si basa sulla media. Se i tuoi dati contengono degli outliers (valori estremi dovuti a errori di tracciamento o bug), la media verrà trascinata verso l’alto o verso il basso, falsando la [math]t\text{-statistic}[/math].
Check: Hai visualizzato i dati con un boxplot o un istogramma?
Soluzione: Se i dati sono fortemente asimmetrici o pieni di outliers, il Test t non è adatto. Usa il Test di Mann-Whitney (U-test), che è l’equivalente non parametrico basato sui ranghi (posizioni) e non sulle medie.
2. Dimensione del campione e “p-hacking”
Se continui a monitorare il [math]p\text{-value}[/math] ogni ora mentre i dati arrivano e decidi di fermarti non appena vedi [math]p < 0.05[/math], stai barando (anche se non lo sai). Questo si chiama p-hacking.
Check: Hai stabilito la dimensione del campione prima di iniziare il test?
Soluzione: Definisci la dimensione del campione necessaria tramite una Power Analysis. Una volta raggiunto quel numero, fermati e analizza i dati. Non prima.
3. Assunzioni sulla Varianza (Omoschedasticità)
Lo abbiamo visto con il Test di Welch: dare per scontato che i due gruppi oscillino allo stesso modo è un rischio inutile.
Check: I due gruppi hanno una varianza simile?
Soluzione: Se non vuoi rischiare, usa sempre equal_var=False. Non c’è quasi mai un reale svantaggio nell’usare Welch invece dello Student classico, ma c’è un enorme vantaggio in termini di robustezza.
4. L’errore di interpretazione: Significatività vs Realtà
Questo è l’errore “aziendale” più frequente. Un test può essere statisticamente significativo ma totalmente irrilevante a livello pratico.
Check: Hai calcolato il d di Cohen o un’altra misura di Effect Size?
Soluzione: Se il [math]p\text{-value}[/math] è [math]0.001[/math] ma il d di Cohen è [math]0.1[/math], hai trovato una differenza che esiste, ma è talmente piccola che probabilmente non sposterà di un millimetro il fatturato aziendale.
Esercizio di debug: Trova l’errore
Immagina di ricevere questo report da un collega:
“Ho analizzato il tempo di permanenza sul sito. Il gruppo A ha una media di 40s, il gruppo B di 42s. Il test t dice [math]p = 0.048[/math]. Abbiamo vinto, implementiamo la versione B!”
Perché dovresti essere scettico?
- Marginalità: Il [math]p\text{-value}[/math] è pericolosamente vicino alla soglia di [math]0.05[/math]. Potrebbe essere un falso positivo.
- Mancanza di contesto: Qual è la deviazione standard? Se è molto alta, quella differenza di 2 secondi è solo rumore.
- Assenza di Effect Size: Senza il d di Cohen, non sappiamo se quei 2 secondi giustifichino i costi di migrazione dei server o di design.
Note finali per la Parte 1
Questa prima parte ci ha insegnato a non fidarci ciecamente di una funzione Python. Abbiamo visto che stats.ttest_ind è un’arma potente, ma va impugnata con la consapevolezza del Test di Welch e dell’Effect Size.
Articoli di approfondimento
👉 Il p-value: questo sconosciuto (episodio 1)
👉 Il p-value spiegato in modo chiaro
👉 Outlier: come trovarli e gestirli con IQR e Z-score
👉 Statistica inferenziale: esercizi progressivi
👉 Test t di Student: esercizi pratici





