Vai al contenuto principale
Stima e intervalli - immagine ufficiale della lezione su GinnyTech, creata da AD

Stima, errore standard e intervalli di confidenza

Come stimare parametri dai dati e quantificare l'incertezza della stima.

AD
Creato daAndrii Dyshkantiuk
Lezione 156 / 236Livello: AvanzatoDurata: 22 minPrerequisiti: 1

Cosa imparerai

  • Calcolare l'errore standard SE = σ/√n e dimensionare il campione per l'effetto atteso
  • Costruire intervalli di confidenza al 95% e interpretarli come valori compatibili con i dati
  • Ricavare intervalli bootstrap sui percentili quando la metrica è asimmetrica

Stima, errore standard e intervalli di confidenza

Siamo nel binario ml-tabellare, e la domanda di oggi nasce da una tabella di sondaggi. Un report dice che la soddisfazione media dei clienti è salita da 7,4 a 7,7. Sembra una buona notizia, finché qualcuno chiede quanto siamo sicuri che non sia solo rumore del campione. Da quella domanda dipende se festeggiare, indagare o non fare nulla. Stima, errore standard e intervalli di confidenza servono a mettere un margine di onestà intorno ai numeri: non cancellano l’incertezza, la rendono visibile.

Che cosa significa stimare con onestà

Ogni stima campionaria va accompagnata dal margine che dice quanto ballerebbe se il campione cambiasse.

Come si costruisce una stima onesta

  1. Definisci popolazione, campione e stimatore prima di raccogliere i dati.
  2. Calcola la stima puntuale, per esempio la media campionaria x̄.
  3. Calcola l’errore standard con SE = σ/√n, usando s al posto di σ se ignota.
  4. Costruisci l’intervallo al 95% come stima ± 1.96 × SE quando vale l’approssimazione normale.
  5. Se la distribuzione è ignota o asimmetrica, ricava l’intervallo con il bootstrap sui percentili 2.5 e 97.5.
  6. Leggi l’intervallo come insieme di valori compatibili con i dati, non come garanzia sul parametro.

L’errore standard: quanto la stima balla

L’errore standard (SE) di una stima è la deviazione standard della distribuzione campionaria dello stimatore. Risponde a una domanda diretta: se ripetessi questo studio molte volte, quanto varierebbero le stime? Per la media campionaria vale SE(x̄) = σ/√n.

Ci sono due modi per ridurre l’errore standard. Puoi aumentare n, tenendo presente che la radice quadrata impone di quadruplicare n per dimezzare SE, oppure ridurre σ, cosa non sempre possibile. L’impatto è concreto. Un A/B test con n=10.000 e conversione baseline p=0.10 ha SE = √(p(1-p)/n) = √(0.09/10000) = 0.003, quindi rilevi differenze di circa 0,6 punti percentuali (2×SE). Se l’effetto atteso è 0,2%, ti servono circa 90.000 utenti.

Intervalli di confidenza: il significato corretto

Un intervallo di confidenza al 95% non significa che c’è una probabilità del 95% che il vero parametro sia nell’intervallo. Quella è l’interpretazione bayesiana, che richiede un prior. Significa invece che, se ripetessi l’esperimento infinite volte e costruissi un intervallo con questo metodo ogni volta, il 95% degli intervalli conterrebbe il vero parametro.

Nella pratica l’intervallo serve a due cose. La prima è darti un intervallo di valori compatibili con i dati: gli effetti tra ci_lower e ci_upper sono ragionevoli dato il campione. La seconda è funzionare come test d’ipotesi incorporato, perché se l’intervallo non include lo zero l’effetto è statisticamente significativo. Il problema più comune è l’errore di interpretazione: dire che il vero effetto è tra 1% e 3% come se fosse una certezza. Non lo è.

Il bootstrap: quando non puoi assumere normalità

Cosa fai quando la distribuzione del tuo stimatore non è normale, cioè quasi sempre per le metriche di business? Il bootstrap di Efron del 1979 è geniale nella sua semplicità. Campioni con ripetizione dal dataset originale N volte, calcoli la stima su ogni campione e la distribuzione empirica delle stime bootstrap approssima bene la distribuzione campionaria. I percentili 2.5 e 97.5 sono il tuo intervallo di confidenza bootstrap.

def bootstrap_ci(data, stat_func, n_boot=10000):
    boots = [stat_func(np.random.choice(data, len(data))) for _ in range(n_boot)]
    return np.percentile(boots, [2.5, 97.5])

ci = bootstrap_ci(revenues, np.mean)  # [82.3, 97.8]

Verdetto: usa l’intervallo analitico quando normalità e indipendenza tengono, il bootstrap quando le metriche sono asimmetriche o non normali, e non pubblicare mai una stima puntuale senza uno dei due.

Riferimenti:

  • Efron, B. (1979). “Bootstrap Methods: Another Look at the Jackknife.” Annals of Statistics, 7(1).
  • Efron, B. & Tibshirani, R.J. (1993). An Introduction to the Bootstrap. Chapman & Hall.

Esempio SQL: costruire una vista di controllo

La vista seguente crea una base analitica con metrica, segmento e finestra temporale, così puoi confrontare periodi e gruppi senza riscrivere la logica ogni volta.

WITH base_events AS (
  SELECT
    user_id,
    account_id,
    event_type,
    event_time,
    DATE_TRUNC('week', event_time) AS week,
    source,
    device_type
  FROM events
  WHERE event_time >= CURRENT_DATE - INTERVAL '180 days'
    AND user_id IS NOT NULL
),
weekly_user_metrics AS (
  SELECT
    week,
    user_id,
    COALESCE(source, 'unknown') AS source,
    COALESCE(device_type, 'unknown') AS device_type,
    COUNT(*) AS total_events,
    COUNT(DISTINCT DATE(event_time)) AS active_days,
    COUNT(DISTINCT event_type) AS event_diversity,
    MAX(CASE WHEN event_type IN ('purchase', 'subscribe', 'activation') THEN 1 ELSE 0 END) AS reached_key_outcome
  FROM base_events
  GROUP BY week, user_id, source, device_type
)
SELECT
  week,
  source,
  device_type,
  COUNT(DISTINCT user_id) AS users,
  ROUND(AVG(active_days), 2) AS avg_active_days,
  ROUND(AVG(event_diversity), 2) AS avg_event_diversity,
  ROUND(AVG(reached_key_outcome) * 100, 2) AS key_outcome_rate
FROM weekly_user_metrics
GROUP BY week, source, device_type
ORDER BY week, source, device_type;

Esempio Python: controllare stabilità e anomalie

Il controllo seguente segnala variazioni anomale settimana su settimana senza reagire a ogni oscillazione casuale.


# df contiene: week, segment, users, key_outcome_rate
# key_outcome_rate espresso in percentuale, es. 12.4

df = df.sort_values(['segment', 'week']).copy()
df['previous_rate'] = df.groupby('segment')['key_outcome_rate'].shift(1)
df['wow_change_pp'] = df['key_outcome_rate'] - df['previous_rate']
df['rolling_mean'] = df.groupby('segment')['key_outcome_rate'].transform(
    lambda s: s.rolling(4, min_periods=2).mean()
)
df['rolling_std'] = df.groupby('segment')['key_outcome_rate'].transform(
    lambda s: s.rolling(4, min_periods=2).std()
)
df['z_score'] = (df['key_outcome_rate'] - df['rolling_mean']) / df['rolling_std']

anomalies = df[df['z_score'].abs() >= 2].sort_values('z_score')
print(anomalies[['week', 'segment', 'key_outcome_rate', 'wow_change_pp', 'z_score']])

1936: quando il campione enorme sbagliò tutto

Alle presidenziali americane del 1936 il Literary Digest raccolse 2,4 milioni di schede e previde la vittoria di Alf Landon su Franklin Roosevelt. George Gallup, con circa 50.000 interviste su un campione stratificato, previde correttamente la vittoria di Roosevelt. Il campione enorme del Digest era autoselezionato tra abbonati, proprietari di auto e di telefono, quindi distorto all’origine; quello piccolo di Gallup era rappresentativo. La lezione resta valida: nella stima la rappresentatività batte la numerosità.

Quattro domande per chiudere

  1. Perché quadruplicare il campione dimezza l’errore invece di azzerarlo?
  2. Quando un intervallo al 95% viene letto nel modo sbagliato più spesso?
  3. Cosa fai se la metrica è troppo asimmetrica per l’intervallo normale?
  4. Quale controllo fai prima di confrontare due stime con il loro errore?
Serve una mano concreta?

Bloccato su questo argomento o vuoi applicarlo al tuo caso? Prenota una call di 15 minuti con un analista esperto.

Prenota una call