Go to main content
Estimation and Intervals - official lesson image on GinnyTech, created by AD

Estimation, standard error, and confidence intervals

How to estimate parameters from data and quantify the uncertainty of the estimate.

AD
Created byAndrii Dyshkantiuk
Lesson 156 / 236Level: AdvancedDuration: 22 minPrerequisites: 1

What you will learn

  • 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

Estimation, standard error, and confidence intervals

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 instead of σ 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.

Standard Error: how much the estimate wobbles

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 has 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.

Confidence Intervals: the correct meaning

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 è.

Bootstrap: when you cannot assume normality

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.

References:

  • 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.

SQL example: building a control view

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;

Python example: checking stability and anomalies

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.

Book a call