Perché non si può valutare un modello sui dati di addestramento
Dimostrerà il data leakage valutando un modello che ha memorizzato i dati e vedrà perché i dati di test separati sono essenziali per stimare onestamente le prestazioni.
Perché non si può valutare un modello sui dati di addestramento è una lezione Machine Learning Academy gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Machine Learning Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Machine Learning Academy include 4 lezioni in totale.
Il problema della valutazione
Dopo aver addestrato un modello, la cosa più invitante da fare è testarlo sugli stessi dati utilizzati per l'addestramento. Il modello probabilmente otterrà un punteggio molto alto, talvolta un'accuracy del 100%, e questo può sembrare un successo. Non lo è. Si tratta dell'errore più fondamentale nel machine learning e produce risultati del tutto inutili per prevedere le prestazioni nel mondo reale.
Comprendere perché questo approccio fallisce non è solo una questione tecnica: cambia il modo in cui si considera l'obiettivo complessivo del machine learning. L'obiettivo non è mai ottenere buone prestazioni sui dati di addestramento. L'obiettivo è sempre generalizzare a dati nuovi e non ancora osservati.
Memorizzazione e generalizzazione
Consideri la differenza tra uno studente che memorizza ogni risposta di un libro di preparazione agli esami e uno che comprende davvero la materia. Il primo studente risolve perfettamente ogni esercizio di prova, ma fallisce quando l'esame reale presenta formulazioni leggermente diverse. Il secondo potrebbe non ottenere risultati perfetti negli esercizi di prova, ma affronta con sicurezza le domande nuove.
Un modello di ML che «memorizza» gli esempi di addestramento (un modello fortemente overfittato) si comporta esattamente come il primo studente. Ottiene un'accuracy di addestramento perfetta, ma fallisce su nuovi input. Questo fenomeno viene chiamato data leakage quando si verifica durante la valutazione: le risposte sono state «fatte trapelare» nel test.
Una dimostrazione: la memorizzazione in azione
Dimostriamolo empiricamente. Un albero decisionale con profondità illimitata memorizzerà perfettamente ogni esempio di addestramento, raggiungendo un'accuracy di addestramento del 100%. Tuttavia, la sua accuracy sul test sarà molto più bassa, perché avrà imparato il rumore invece del vero schema sottostante.
Questo esperimento rende il problema concreto e misurabile: l'accuracy di addestramento non è significativa come stima delle prestazioni; misura la memoria, non l'intelligenza.
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# Unlimited depth: memorises training data
model = DecisionTreeClassifier() # no max_depth limit
model.fit(X_train, y_train)
train_acc = model.score(X_train, y_train)
test_acc = model.score(X_test, y_test)
print(f'Training accuracy: {train_acc:.3f}') # 1.000 -- perfect memorisation
print(f'Test accuracy: {test_acc:.3f}') # much lower
print(f'Overfit gap: {train_acc - test_acc:.3f}')Perché l'accuracy di addestramento è distorta verso l'alto
I parametri del modello sono stati ottimizzati appositamente per ridurre al minimo l'errore sul set di addestramento. Ciò significa che, per qualsiasi modello ragionevolmente complesso, l'errore di addestramento è certamente inferiore al vero errore di generalizzazione. Il divario tra errore di addestramento ed errore di test è chiamato ottimismo dell'errore di addestramento.
Quanto più numerosi sono i parametri di un modello rispetto agli esempi di addestramento, tanto più grave è l'ottimismo. Una rete neurale con milioni di parametri e soltanto 1.000 esempi di addestramento può facilmente raggiungere un errore di addestramento dello 0%, mentre il suo vero tasso di errore è del 50%. L'errore di addestramento non è una stima affidabile della generalizzazione: punto.
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
import numpy as np
X, y = make_classification(n_samples=500, n_features=20, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
# KNN with k=1: memorises perfectly (always finds the exact training point)
knn1 = KNeighborsClassifier(n_neighbors=1)
knn1.fit(X_train, y_train)
print(f'k=1 Training accuracy: {knn1.score(X_train, y_train):.3f}') # 1.000
print(f'k=1 Test accuracy: {knn1.score(X_test, y_test):.3f}') # lower
# k=10: generalisers better
knn10 = KNeighborsClassifier(n_neighbors=10)
knn10.fit(X_train, y_train)
print(f'k=10 Test accuracy: {knn10.score(X_test, y_test):.3f}')Il set di test separato: la soluzione
La soluzione è semplice, ma deve essere applicata con rigore: riservi una parte dei dati prima di iniziare qualsiasi attività di modellazione e non la utilizzi mai per l'addestramento né per prendere decisioni che influenzino il modello.
Questo set di test separato è una stima onesta delle prestazioni di generalizzazione. Poiché il modello non lo ha mai visto, le sue prestazioni su questo set sono la migliore stima disponibile del comportamento su dati futuri. Il set di test è uno strumento di misurazione da utilizzare una sola volta: usarlo più volte per ottimizzare il modello lo rende inutilizzabile.
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
import numpy as np
X, y = load_breast_cancer(return_X_y=True)
# CORRECT workflow: split BEFORE any analysis
X_train, X_test, y_train, y_test = train_test_split(
X, y,
test_size=0.20, # 20% held out for final evaluation only
random_state=42, # reproducible split
stratify=y # maintain class ratio in both splits
)
print(f'Training set: {X_train.shape[0]} examples')
print(f'Test set: {X_test.shape[0]} examples')
print(f'Train class balance: {y_train.mean():.3f}')
print(f'Test class balance: {y_test.mean():.3f}')Data leakage: la versione più insidiosa
Usare dati di test per la valutazione finale è la forma più evidente di fuga di dati. Esistono forme più sottili, ma altrettanto dannose:
- Fuga durante il preprocessing: adattare uno scaler all'intero dataset prima della suddivisione, quindi applicarlo ai dati di addestramento e di test: lo scaler ha "visto" le statistiche dei dati di test.
- Fuga dalle feature: includere una feature derivata dalla variabile target, ad esempio un flag "diagnosi confermata" impostato solo quando il paziente è effettivamente malato.
- Fuga temporale: usare dati futuri per prevedere eventi passati, ad esempio includere i dati sulle vendite del terzo trimestre per prevedere i risultati del primo trimestre.
from sklearn.preprocessing import StandardScaler
import numpy as np
# WRONG: fit scaler on full dataset before splitting
X = np.random.randn(1000, 5)
scaler_wrong = StandardScaler()
X_scaled_all = scaler_wrong.fit_transform(X) # leakage! scaler saw test data
# Correct: split first, then fit scaler ONLY on training data
from sklearn.model_selection import train_test_split
X_train, X_test = train_test_split(X, test_size=0.2)
scaler_correct = StandardScaler()
X_train_s = scaler_correct.fit_transform(X_train) # fit on train only
X_test_s = scaler_correct.transform(X_test) # apply to test
print('Correct preprocessing: scaler fitted on training data only.')Suddivisione in tre parti: addestramento, convalida e test
Quando usa l'insieme di test per prendere decisioni, ad esempio scegliere tra due modelli o selezionare una soglia, questo insieme non fornisce più una stima corretta della generalizzazione. Per mantenerlo incontaminato, introduca un insieme di convalida:
- Insieme di addestramento: per adattare i parametri del modello.
- Insieme di convalida: per ottimizzare gli iperparametri, selezionare i modelli e modificare le soglie.
- Insieme di test: per la valutazione finale, da eseguire una sola volta. Lo utilizzi soltanto alla fine.
Una suddivisione comune è 70% addestramento / 15% convalida / 15% test. La cross-validation offre un'alternativa più efficiente, facendo ruotare i fold di convalida all'interno dell'insieme di addestramento.
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
X, y = load_breast_cancer(return_X_y=True)
# First split off test set (15%)
X_temp, X_test, y_temp, y_test = train_test_split(X, y, test_size=0.15, random_state=42)
# Then split remaining into train and validation
X_train, X_val, y_train, y_val = train_test_split(X_temp, y_temp, test_size=0.176, random_state=42)
# 0.176 of 85% ≈ 15% of the original
print(f'Train: {X_train.shape[0]}')
print(f'Val: {X_val.shape[0]}')
print(f'Test: {X_test.shape[0]}')Come la contaminazione dell'insieme di test gonfia i risultati
Supponga di addestrare 10 modelli diversi, valutarli tutti sull'insieme di test e scegliere quello con l'accuratezza di test più alta. Questo processo ha contaminato l'insieme di test: ha usato le prestazioni sul test per prendere una decisione sul modello. Il modello selezionato è ottimizzato per l'insieme di test e la sua accuratezza dichiarata è ora eccessivamente ottimistica.
È esattamente per questo che competizioni come Kaggle hanno una classifica pubblica (insieme di convalida) e una classifica privata (vero insieme di test, rivelato solo alla fine). I team che fanno overfitting sulla classifica pubblica effettuando numerose submission spesso ottengono risultati scarsi nella classifica privata.
from sklearn.datasets import make_classification
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
import numpy as np
X, y = make_classification(n_samples=500, random_state=99)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
# Contamination: picking best max_depth based on test set
best_acc, best_depth = 0, 1
for depth in range(1, 20):
model = DecisionTreeClassifier(max_depth=depth)
model.fit(X_train, y_train)
acc = model.score(X_test, y_test)
if acc > best_acc:
best_acc, best_depth = acc, depth
print(f'Best depth selected by test: {best_depth}, acc: {best_acc:.3f}')
print('This accuracy is now overly optimistic!')Riproducibilità: il parametro random_state
Il parametro random_state in train_test_split controlla quali esempi finiscono in ciascuna suddivisione. Senza questo parametro, ogni esecuzione produce una suddivisione diversa, rendendo difficile riprodurre e confrontare i risultati.
Imposti sempre random_state su un intero fisso in tutto il codice che condivide con altri o che desidera riprodurre in seguito. Va bene qualsiasi intero: per convenzione si usano 42, 0 o 1, purché documenti il valore utilizzato. Il valore specifico dell'intero non è importante; lo è la coerenza.
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris
X, y = load_iris(return_X_y=True)
# Without random_state: different results every run
X_train1, X_test1, _, _ = train_test_split(X, y) # no seed
X_train2, X_test2, _, _ = train_test_split(X, y) # no seed
print('Different splits without seed:', not (X_train1 == X_train2).all())
# With random_state: same result every run
X_train3, X_test3, _, _ = train_test_split(X, y, random_state=42)
X_train4, X_test4, _, _ = train_test_split(X, y, random_state=42)
print('Same splits with seed:', (X_train3 == X_train4).all())La regola d'oro della valutazione ML
L'unica regola che riassume tutto ciò che viene spiegato in questa lezione è: l'insieme di test non deve mai influenzare alcuna decisione presa durante lo sviluppo del modello. Questo significa:
- Nessun preprocessing adattato sui dati di test.
- Nessun modello selezionato in base alle prestazioni sul test.
- Nessuna soglia ottimizzata in base alle prestazioni sul test.
- Nessuna feature progettata dopo aver esaminato gli errori sul test.
- L'insieme di test va utilizzato una sola volta, alla fine, per riportare le prestazioni finali.
Seguire questa regola garantisce che le prestazioni dichiarate siano una stima onesta del comportamento del modello in produzione su dati futuri.
Verifica rapida
Verifichi la Sua comprensione dei concetti di Machine Learning con Python presentati in questa lezione.
Riepilogo della lezione
In questa lezione ha imparato che: l'accuratezza sull'addestramento è sempre influenzata da un bias ottimistico, perché i parametri del modello sono stati ottimizzati su quei dati, un insieme di test separato, che non influenza mai alcuna decisione sull'addestramento, fornisce una stima onesta della generalizzazione e la fuga di dati, inclusa quella durante il preprocessing e la contaminazione dell'insieme di test, produce stime delle prestazioni ingannevolmente elevate. Ora approfondiremo la funzione train_test_split di scikit-learn, analizzando i rapporti tra le dimensioni degli insiemi, i semi casuali e la stratificazione per i problemi di classificazione sbilanciati.
Impara Python con un tutor IA — gratis
Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.
- Corsi
- 30
- Lezioni
- 120
Domande Frequenti
La lezione «Perché non si può valutare un modello sui dati di addestramento» è gratuita?
Sì — il testo completo di «Perché non si può valutare un modello sui dati di addestramento» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Machine Learning Academy, passa a CoddyKit PRO. Il corso Machine Learning Academy include 4 lezioni in totale.
Cosa imparerò in «Perché non si può valutare un modello sui dati di addestramento»?
Dimostrerà il data leakage valutando un modello che ha memorizzato i dati e vedrà perché i dati di test separati sono essenziali per stimare onestamente le prestazioni. Eserciti Machine Learning Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Machine Learning Academy?
Non è richiesta alcuna esperienza precedente. Machine Learning Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.
Quanto tempo richiede la lezione «Perché non si può valutare un modello sui dati di addestramento»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Machine Learning Academy?
Sì. Ogni lezione Machine Learning Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Perché non si può valutare un modello sui dati di addestramento
- train_test_split: proporzioni, seed e stratificazione
- Compromesso bias-varianza: underfitting e overfitting
- Modelli baseline: battere sempre il classificatore dummy