Go to main content
Evaluation: leakage, drift, metrics, and limits - GinnyTech header image with an editorial cosmic visual

Evaluation: leakage, drift, metrics, and limits

Evaluation: leakage, drift, metrics, and limits on GinnyTech: decide if a model can enter the process or must remain a controlled experiment with controls, ownership, and reviewable outputs.

AD
Created byAndrii Dyshkantiuk
Lesson 224 / 236Level: AdvancedDuration: 31 minPrerequisites: 1

What you will learn

  • Design AI workflows for data with controls, owners, and reviewable outputs
  • Apply AI, AutoML or agentic AI to business analytics cases without losing rigor
  • Recognize risks of leakage, drift, cost, privacy, and ungoverned automation

Evaluation: leakage, drift, metrics, and limits

Questo binario, dedicato ai sistemi LLM e AI applicati al lavoro sui dati, comincia da una verità scomoda: un modello che brilla sul notebook e crolla nella prima settimana in produzione non ha avuto sfortuna. È stato valutato male. Il problema è che troppo spesso la valutazione viene trattata come l’ultima formalità della pipeline, una tabella di metriche da allegare al report, invece che come il meccanismo che decide se il modello merita di toccare una decisione reale. La differenza tra un esperimento convincente e un sistema affidabile sta quasi tutta qui: negli split temporali, nelle feature che non dovevano esserci, nella metrica scelta per compiacere invece che per prevedere il costo dell’errore, nel monitoraggio che nessuno ha scritto.

La posta in gioco, in due righe

La valutazione stabilisce — con split temporali, metriche legate al costo dell’errore e monitoraggio continuo — se un modello può sostenere una decisione reale o deve restare un esperimento controllato. Non è un atto finale, ma un dispositivo di governo che ti dice quando fidarti e quando fermarti.

Un percorso in sei passi

Ecco il metodo, ridotto all’ordine giusto di esecuzione.

  1. Elenca ogni feature con il momento in cui il valore era davvero disponibile e scarta quelle che guardano al futuro.
  2. Disegna lo split che replica l’uso reale: temporale con embargo per le serie storiche, per gruppi quando la stessa entità genera più righe.
  3. Fissa la baseline onesta e la metrica legata al costo dell’errore, con soglia decisionale scritta prima di confrontare i modelli.
  4. Misura la metrica per segmento, verifica la calibrazione delle probabilità e disegna la curva profitto per soglia.
  5. Confronta split casuale e split temporale: se il divario è ampio, cerca la perdita prima di festeggiare.
  6. Metti in produzione solo con telemetria su dati, predizioni ed esiti, dominio di validità dichiarato e rollback testato.

Perché un buon punteggio in laboratorio dice poco

Il numero che leggi su un test set vale solo quanto vale il protocollo che lo ha prodotto. Se lo split è casuale su dati con struttura temporale, se le feature contengono proxy dell’etichetta, se la metrica media nasconde segmenti dove il modello è dannoso, quel numero è decorativo. I pattern sono ricorrenti e li riconosci a occhio chiuso: il lead scoring che aveva imparato a riconoscere i lead già contattati dal commerciale, informazione indisponibile al momento della predizione reale; il classificatore di churn con accuratezza altissima su una base dove la classe dominante rende banale anche il predittore costante; il forecast validato su settimane intercambiabili invece che su finestre consecutive, cieco alla stagionalità.

Il filo comune è che la valutazione non risponde a “quanto è bravo il modello in astratto”, ma a “quanto peggiora quando lo sposto dal passato che conosco al futuro che non conosco, con i dati davvero disponibili al momento della decisione”. Ogni scelta — split, feature, metrica, baseline — deve rendere quella distanza visibile, non nasconderla. E qui arriva un punto che molti saltano: una baseline onesta aiuta più di un modello sofisticato. Il forecast naive stagionale, la regola euristica del team commerciale, il modello già in produzione: se il nuovo modello non batte la baseline sul protocollo giusto, non c’è deploy da discutere.

Vale anche il principio opposto, ed è bene dirlo con chiarezza: un protocollo troppo pessimistico paralizza. Bloccare un modello perché fallisce su segmenti rari e irrilevanti, o perché una metrica secondaria peggiora mentre quella legata al costo migliora nettamente, è valutazione difensiva, non rigorosa. Il rigore sta nel collegare ogni numero a una decisione: cosa cambia se la metrica sale o scende, chi decide, con quale soglia, con quale piano di rollback.

Il leakage: quando il futuro si infila nel training set

Il leakage è informazione sul target che entra nelle feature attraverso un canale indisponibile al momento della predizione. È l’errore più pericoloso perché gonfia le metriche invece di abbassarle: il modello sembra migliorare proprio mentre diventa inutile. E spesso non è un singolo campo sospetto, ma una catena di trasformazioni — join, aggregazioni, imputazioni, normalizzazioni — calcolate sull’intero dataset prima dello split.

Le forme ricorrenti sono poche e vale la pena saperle riconoscere al primo sguardo. Il leakage diretto è il caso banale: una colonna come data_chiusura_contratto o esito_verifica_manuale che è una conseguenza dell’evento da predire. Il leakage da join temporale è più subdolo: arricchisci ogni riga con dati anagrafici o comportamentali aggiornati a oggi, mentre al momento della predizione avresti avuto solo lo stato di allora. Il leakage da preprocessing nasce quando imputi i mancanti, standardizzi o fai target encoding sull’intero dataset prima di separare train e test: le statistiche del test contaminano il training. C’è poi il leakage da duplicati e da entità: stesso utente, stesso dispositivo o stesso documento presente sia in train che in test, così il modello memorizza invece di generalizzare. Nei dati temporali, infine, lo split casuale è di per sé leakage: il futuro finisce nel training e il passato nel test, e il modello impara pattern che non potrà mai usare.

Il sintomo classico è un gap sospetto: performance stellari in validazione e crollo in produzione, oppure un modello che assegna importanza enorme a una feature che nessun domain expert trova plausibile. Un altro segnale è la feature “troppo predittiva”: se rimuovendola la metrica crolla, quella colonna meritava un audit temporale prima di festeggiare. La regola operativa è semplice da enunciare e faticosa da applicare: per ogni feature, chiediti a quale timestamp sarebbe stato realmente disponibile quel valore per quella specifica istanza, e da quale tabella deriva.

La prevenzione è architetturale. Si calcola ogni feature con semantica point-in-time: aggregazioni troncate alla data di predizione, mai a oggi. Si incapsula tutto il preprocessing dentro una pipeline fittata solo sul train, mai fit su train più test. Si deduplica per entità prima dello split, e si ragiona per gruppi quando la stessa entità genera più righe. C’è poi un controllo economico che intercetta gran parte dei casi: allena lo stesso modello due volte, una con la feature sospetta e una senza, su split temporale rigoroso. Se il contributo della feature evapora nello split temporale ma persiste in quello casuale, hai trovato la perdita.

# Confronto split casuale vs temporale per stanare il leakage
# Ogni riga ha un timestamp di predizione: lo split temporale lo rispetta,
# quello casuale mescola passato e futuro e nasconde la perdita.
from sklearn.model_selection import train_test_split
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.metrics import roc_auc_score

# Ordinamento temporale: il test e il futuro, il train e il passato
df = df.sort_values("prediction_timestamp").reset_index(drop=True)
cutoff = int(len(df) * 0.8)
train_time, test_time = df.iloc[:cutoff], df.iloc[cutoff:]

# Split casuale: rapido ma ottimista su dati temporali
train_rand, test_rand = train_test_split(df, test_size=0.2, random_state=42)

def valuta(train, test, feature_cols):
    # Il modello vede solo le colonne dichiarate come disponibili al prediction time
    modello = HistGradientBoostingClassifier(random_state=42)
    modello.fit(train[feature_cols], train["target"])
    predette = modello.predict_proba(test[feature_cols])[:, 1]
    return roc_auc_score(test["target"], predette)

# Se lo split casuale da 0,95 e quello temporale 0,72, indaga le feature
print("Casuale:", valuta(train_rand, test_rand, FEATURES))
print("Temporale:", valuta(train_time, test_time, FEATURES))

Come si progetta una validazione che non mente

Lo split non è un dettaglio burocratico: è la simulazione dell’uso reale. La domanda da porsi è sempre la stessa: quando il modello sarà in produzione, su quali dati dovrà predire, con quale ritardo, e con quale frequenza verrà riaddestrato? Il protocollo di validazione deve replicare quelle condizioni, altrimenti misuri un altro problema.

Per dati indipendenti e identicamente distribuiti — il caso raro, tipico di alcune classificazioni su istanze isolate — lo split stratificato casuale con k-fold cross-validation resta valido. Per tutto ciò che ha tempo, geografia, entità o struttura gerarchica servono schemi più severi. Sui dati temporali si usa lo split forward: train sul passato, validation su una finestra successiva, test su una ancora successiva, con un embargo tra le finestre se le etichette si consolidano in ritardo. Quando il modello verrà riaddestrato ogni settimana, la validazione deve simulare quel ciclo con rolling window o expanding window, non con un singolo split. Quando la stessa entità genera più osservazioni — utente, negozio, sensore — serve GroupKFold per gruppi: nessuna entità a cavallo tra train e test, altrimenti misuri memoria, non generalizzazione.

SituationSchema correttoErrore frequente
Serie temporali, forecastSplit temporale, rolling window, embargoK-fold casuale che mescola futuro e passato
Righe raggruppate per entitàGroupKFold per utente, negozio, documentoStesso utente in train e test
Classi rare o sbilanciateSplit stratificato per target e segmentoFold senza positivi, metriche instabili
Riaddestramento periodicoBacktest che replica la cadenza realeSingolo split che ignora il retraining
Etichette che maturano in ritardoEmbargo tra train e testTest con etichette parziali o provvisorie

Due accorgimenti separano i protocolli seri da quelli decorativi. Il primo è il purging con embargo nelle serie finanziarie e comportamentali: se l’etichetta alla data t dipende da eventi fino a t + h, le istanze di training vicine al test vanno scartate, altrimenti il futuro filtra attraverso la finestra di label. Il secondo è la nested cross-validation quando si fa tuning degli iperparametri: un loop esterno misura la generalizzazione, un loop interno sceglie gli iperparametri. Senza nesting, il test set partecipa di fatto alla selezione del modello e le metriche risultano ottimiste di qualche punto — abbastanza per scegliere il modello sbagliato.

Le metriche giuste per il problema giusto

La metrica è una dichiarazione di priorità, non una proprietà matematica neutra. Sceglierla significa rispondere a: quale errore costa di più, su quale segmento, e con quale tolleranza al rumore? L’accuracy è quasi sempre la risposta sbagliata quando le classi sono sbilanciate o i costi asimmetrici, eppure resta la più citata per il motivo più triste: è la più facile da spiegare in riunione.

In classificazione conviene ragionare per coppie. Precision e recall descrivono il trade-off fondamentale: la precision è la quota di veri positivi tra i positivi predetti, il recall è la quota di veri positivi tra i positivi reali. La media armonica F1 li combina quando serve un singolo numero, e la variante F-beta pesa di più il recall quando i falsi negativi costano di più — tipico in diagnostica o frodi. Le curve di ranking misurano la capacità di ordinamento su tutte le soglie: utili per confrontare modelli, fuorvianti su dataset molto sbilanciati dove la curva precision-recall racconta meglio la realtà operativa. La matrice di confusione resta lo strumento più onesto: mostra dove il modello sbaglia invece di comprimerlo in uno scalare. E su classi rare, gli intervalli di confidenza contano più del punto stimato: una precision del 60% su 20 casi ha un’incertezza che la rende indistinguibile dal 40%.

In regressione la scelta è tra penalizzare gli errori grandi o raccontare la dispersione tipica. L’errore quadratico medio amplifica gli outlier per costruzione; l’errore assoluto medio descrive l’errore tipico in unità originali ed è più leggibile per gli stakeholder. Le metriche percentuali sembrano comode ma esplodono vicino allo zero e premiano sistematicamente la sottostima: su domanda intermittente o basse numeriche sono inaffidabili. Quando esiste un forecast naive — replica dell’ultimo periodo, media stagionale — la metrica relativa contro il naive dice se il modello batte davvero il banale: un valore sopra 1 significa che la media stagionale farebbe meglio del tuo modello, informazione che l’errore assoluto da solo non dà mai.

Per il forecasting valgono regole aggiuntive. Si valuta sempre su orizzonti multipli e per granularità rilevante: un modello ottimo a 7 giorni e pessimo a 30 va saputo prima del deploy, non dopo. Si separa l’errore per regime — settimane normali contro picchi, promozioni, festività — perché la media nasconde i fallimenti costosi. E si misura l’errore cumulato sull’orizzonte quando la decisione è cumulata: per il riordino magazzino conta la domanda totale del mese, non la precisione sul singolo giorno.

# Metriche per segmento: la media globale nasconde i fallimenti locali
# Suddividi sempre per i segmenti che guidano la decisione di business.
import numpy as np
from sklearn.metrics import precision_score, recall_score, f1_score

# df_val deve contenere: target vero, predizione e colonna di segmento
for segmento, sotto in df_val.groupby("segmento"):
    prec = precision_score(sotto["y_true"], sotto["y_pred"], zero_division=0)
    rec = recall_score(sotto["y_true"], sotto["y_pred"], zero_division=0)
    f1 = f1_score(sotto["y_true"], sotto["y_pred"], zero_division=0)
    # n positivo: con pochi casi la stima e rumorosa, segnalalo
    print(f"{segmento}: n={len(sotto)} prec={prec:.2f} rec={rec:.2f} F1={f1:.2f}")

La tabella mentale da tenere a portata di mano è questa: classi sbilanciate e ranking, PR-AUC più matrice di confusione; costi asimmetrici, F-beta con beta scelto dal costo; regressione con outlier, MAE affiancato a RMSE; forecast stagionale, MASE contro baseline naive; decisione su soglia, curva profitto invece di una metrica statistica pura.

Oltre l’accuratezza: calibrazione, soglie e costi degli errori

Un modello può ordinare bene i casi e stimare male le probabilità. È una distinzione cruciale quando la probabilità guida un’azione: concedere credito, prenotare scorte, inviare un tecnico. La discriminazione — mettere i positivi sopra i negativi — è ciò che misura la capacità di ranking. La calibrazione — quando dico 70%, l’evento accade davvero il 70% delle volte — è ciò che decide se puoi fidarti del numero. E qui sta il guaio: i boosting e le reti neurali moderne sono spesso miscalibrati verso l’eccesso di confidenza. Ottimo ranking, sì; probabilità estreme e inaffidabili, anche.

Il controllo standard è il reliability diagram: si raggruppano le predizioni in bin di probabilità e si confronta la media predetta con la frequenza osservata. Se la curva sta sistematicamente sopra la diagonale il modello è sottoconfidente, se sta sotto è sovraconfidente. Le riparazioni comuni — Platt scaling, regressione isotonica, temperature scaling — si calibrano su un validation set separato, mai sul test finale, altrimenti si ricade nel leakage da tuning. E la calibrazione va verificata per segmento: un modello calibrato globalmente ma scalibrato sulle PMI ad alto valore prende decisioni costose proprio dove conta.

La soglia decisionale trasforma la probabilità in azione, e la soglia di default 0,5 non ha alcuno statuto speciale: è solo il punto dove i costi dei due errori si equivalgono, caso raro nella realtà. La scelta corretta massimizza il valore atteso: si stimano costo del falso positivo e del falso negativo in euro, ore o rischio, e si cerca la soglia che minimizza il costo totale sul validation. Nel lead scoring, contattare un lead inutile costa una telefonata, perdere un buon lead costa un contratto: la soglia scende. Nella manutenzione predittiva, un falso allarme costa un’ispezione, un guasto mancato costa un fermo impianto: la soglia scende ancora. Nel credito o nella moderazione automatica, dove il falso positivo ha costo legale o reputazionale, la soglia sale. La curva profitto per soglia, disegnata sul validation temporale, rende la scelta discutibile in riunione invece che arbitraria.

Il drift: quando il mondo cambia sotto il modello

Il drift è il degrado delle assunzioni statistiche dopo il deploy, e si presenta in tre forme con tre diagnosi diverse. Il covariate shift cambia la distribuzione degli input a parità di relazione con il target: nuovi segmenti di clientela, nuovi dispositivi, cambio di mix dei canali. Il prior shift cambia la prevalenza delle classi: una frode che passa dallo 0,1% all’1% sposta precision e profitto anche a modello invariato. Il concept drift cambia la relazione stessa tra input e target: una promozione che altera il legame prezzo-domanda, una norma che ridefinisce l’evento da predire. Quest’ultimo è il più grave perché nessun ribilanciamento degli input lo ripara: serve riaddestrare o riprogettare.

La rilevazione combina segnali statistici e di business. Sulle singole feature si usano test di confronto tra finestra di riferimento e finestra corrente: Kolmogorov-Smirnov per numeriche, chi-quadrato per categoriche, Population Stability Index con le sue soglie operative consuete. Sugli embedding o spazi ad alta dimensionalità funzionano meglio distanze dedicate o semplici controlli sulla norma e sulla copertura. Ma il segnale principe resta la performance per segmento sul flusso live con etichette ritardate: se la metrica tiene globalmente e crolla su un segmento in crescita, hai trovato il drift che conta. Il monitoraggio delle predizioni stesse — distribuzione degli score, tasso di positivi predetti — è un proxy utile quando le etichette tardano settimane: se il tasso predetto raddoppia senza motivo di business, qualcosa è cambiato a monte.

# Monitoraggio drift essenziale: PSI per numeriche, confronto tassi per categoriche
# PSI sotto 0,1: variazione modesta; 0,1-0,25: da investigare; oltre 0,25: rottura.
import numpy as np
import pandas as pd

def psi(attese, correnti, n_bin=10):
    # I bin sono definiti sulla finestra di riferimento, mai su quella corrente
    soglie = np.quantile(attese, np.linspace(0, 1, n_bin + 1))
    soglie[0], soglie[-1] = -np.inf, np.inf  # code sempre coperte
    e = pd.cut(attese, soglie).value_counts(normalize=True).sort_index()
    c = pd.cut(correnti, soglie).value_counts(normalize=True).sort_index()
    # Smoothing: evita divisioni per zero nei bin vuoti
    e, c = e.clip(lower=0.0001), c.clip(lower=0.0001)
    return float(((c - e) * np.log(c / e)).sum())

for colonna in FEATURES_NUMERICHE:
    valore = psi(df_riferimento[colonna], df_corrente[colonna])
    stato = "OK" if valore < 0.1 else ("DA INVESTIGARE" if valore < 0.25 else "ROTTURA")
    print(f"{colonna}: PSI={valore:.3f} [{stato}]")

Monitoraggio e limiti operativi in produzione

Un modello senza telemetria è un esperimento lasciato acceso in produzione. Il monitoraggio minimo copre quattro strati. Lo strato dati controlla volumi, completezza, schema e distribuzioni delle feature con soglie di allerta scritte prima del deploy, non improvvisate al primo incidente. Lo strato predizioni traccia distribuzione degli score, tasso di positivi, latenza e tasso di fallback: un improvviso appiattimento degli score spesso segnala una feature a monte andata a null. Lo strato esiti misura la performance ritardata appena le etichette maturano, con finestre coerenti con il ciclo di business e mai con medie cumulative che diluiscono i crolli recenti. Lo strato decisioni registra cosa è stato fatto con la predizione — accettata, scavalcata dall’operatore, ignorata — perché l’override sistematico degli operatori è il segnale più onesto che il modello ha perso utilità.

Servono anche limiti espliciti, non impliciti. Ogni modello ha un dominio di validità: range di feature visti in training, segmenti valutati, orizzonti testati, volumi sostenibili. Fuori da quel dominio il sistema deve degradare con grazia: rifiutare la predizione, instradarla a revisione umana, o applicare una politica conservativa documentata. Il caso tipico è il negozio nuovo senza storico, il paese nuovo senza dati, il prodotto nuovo senza stagionalità: il modello emette comunque un numero, ma quel numero è estrapolazione, non inferenza. Definire a priori le guardrail — copertura minima per segmento, incertezza massima accettabile, tasso di override che fa scattare la review — trasforma il monitoraggio da dashboard decorativa a meccanismo di governo.

Il retraining, poi, non è la risposta automatica a ogni allarme. Se la causa è una pipeline rotta, riaddestrare cementa il danno nei nuovi dati. Se è concept drift genuino, riaddestrare sulla finestra recente aiuta ma va validato con backtest che replica il momento della decisione. Se è un cambiamento strutturale — nuovo listino, nuova normativa, nuovo processo commerciale — serve riprogettare feature ed etichette, non solo rilanciare il fit. La pratica solida prevede finestre di training versionate, artefatti riproducibili e una politica di rollback al modello precedente con un solo comando: il deploy senza rollback testato è una scommessa, non ingegneria.

Una checklist di valutazione prima di firmare il deploy

Prima di portare un modello nel processo, queste domande separano la prontezza reale dall’ottimismo. Ognuna richiede una risposta scritta, non un cenno in riunione.

  • Quale decisione migliora il modello e chi la possiede quando sbaglia?
  • Su quale protocollo temporale è stato validato, con quale embargo e quale baseline battuta?
  • Quali feature entrano nel modello e per ciascuna qual è il timestamp di disponibilità garantito in produzione?
  • Quale metrica primaria guida la scelta e come si traduce in costo per errore?
  • Su quali segmenti la performance è stata verificata separatamente, e dove il modello è peggiore della regola attuale?
  • A quale soglia si trasforma lo score in azione, con quale curva profitto a supporto?
  • Cosa viene monitorato dal giorno uno, con quali soglie di allarme e quale runbook quando scattano?
  • Quali sono i limiti dichiarati del dominio di validità e cosa succede fuori da esso?
  • Qual è il piano di rollback e quando è stato testato l’ultima volta?

Se una sola risposta manca, il modello resta esperimento controllato: utile in shadow mode, pericoloso come decisore. Lo shadow mode — predire senza agire, confrontando con l’esito reale per qualche settimana — è il ponte onesto tra laboratorio e produzione, soprattutto quando le etichette maturano lentamente. Il canary su una frazione di traffico con metriche di guardia viene dopo, mai prima.

Resta un’ultima onestà intellettuale da coltivare: ci sono problemi dove il modello non deve entrare affatto. Dati insufficienti per il segmento che conta, etichette rumorose senza speranza di pulizia, costi degli errori che nessuna soglia rende accettabili, vincoli normativi che richiedono spiegabilità nativa e non post-hoc. Riconoscerlo non è fallimento ma competenza: la valutazione serve anche a dire no, con numeri alla mano, a un deploy che il business desidera ma i dati non sostengono. Il modello migliore è a volte quello non messo in produzione.

Verdetto: split temporale rigoroso, metrica legata al costo e monitoraggio con rollback vincolano più di qualsiasi leaderboard; se una di queste manca, il modello resta in quarantena.

Un caso da manuale: l’early warning di Epic

Nel 2021 la rivista JAMA Internal Medicine pubblicò una validazione esterna del modello di sepsi di Epic, già distribuito in centinaia di ospedali americani. Su quasi 28.000 ricoveri l’area sotto la curva risultò 0,63, molto sotto i valori di 0,76-0,83 dichiarati dal fornitore. Il modello mancava gran parte dei casi reali proprio perché era stato valutato su dati e protocolli scelti da chi lo vendeva. La lezione è quella di questa pagina: conta solo la misura presa sul protocollo giusto, con dati che il modello non ha mai visto e metriche legate al danno reale.

Domande per chiudere la lezione

  1. Per ogni feature del modello, quale data dimostra che il valore esisteva davvero al momento della predizione?
  2. Quando lo split temporale con embargo è obbligatorio e cosa concludi se lo split casuale rende molto di più?
  3. Come fissi la soglia decisionale quando perdere un positivo costa dieci volte un falso allarme?
  4. Quali segnali monitori dal primo giorno in produzione e quale soglia fa scattare il rollback?
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