À la fin de ce laboratoire, vous saurez : 1. Appliquer MLE-STAR à une compétition Kaggle simulée 2. Combiner Web Search + Ablation + Raffinement en workflow complet 3. Générer une soumission compétitive de manière automatisée 4. Itérer sur les améliorations basées sur les résultats
Prérequis
Lab 13 et Lab 14 complétés
Compréhension de MLE-STAR
Configuration multi-provider active
Durée estimée : 50-60 minutes
1. Configuration
Pourquoi ce lab simule une compétition Kaggle plutôt que d’en utiliser une réelle : une compétition Kaggle live impose un dataset volumineux, une cible mouvante (leaderboard) et un coût d’itération élevé — inadapté à un lab pédagogique. Le simulateur reproduit le protocole Kaggle (dataset tabulaire, métrique AUC, leaderboard simulé) sans la lourdeur, pour que l’agent MLE-STAR puisse tourner plusieurs cycles Understand→Search→Generate→Refine dans un temps de notebook. C’est l’écart entre apprendre la méthode (le workflow Kaggle gagnant) et apprendre sur un cas (une compétition précise) : le simulateur isole la méthode.
import syssys.path.insert(0, '..')import jsonimport reimport numpy as npimport pandas as pdfrom typing import List, Dict, Optionalfrom dataclasses import dataclassfrom pathlib import Pathfrom config import get_settingsfrom utils import LLMClientprint("Imports OK : json, re, numpy, pandas, dataclasses, config, utils")
Imports OK : json, re, numpy, pandas, dataclasses, config, utils
Pourquoi un simulateur de compétition plutôt qu’un dataset nu : la valeur pédagogique n’est pas le dataset lui-même mais le protocole Kaggle qu’il déclenche (deadline, métrique publique/privée, leaderboard, itérations). Le simulateur encode ce protocole dans un @dataclass qui expose les dimensions du problème (ici 300 lignes × 8 features pour la Tabular Playground Series) sans révéler la cible — forçant l’agent à explorer avant de modéliser. Sans cette enveloppe de compétition, un notebook ML se réduit à fit/predict ; avec, il devient un cycle d’amélioration mesurable.
@dataclassclass CompetitionInfo: name: str task: str metric: str description: str data_description: strclass KaggleSimulator:def get_competition_info(self) -> CompetitionInfo:return CompetitionInfo( name='Tabular Playground Series', task='binary classification', metric='AUC-ROC', description='Predict customer churn based on tabular features', data_description='20 features numeriques et categoriques, 10000 exemples' )def generate_sample_data(self, n_samples: int=500) -> pd.DataFrame:"""Genere un dataset avec un **signal predictif reel**. #13037 — la version originale creeait `target = np.random.randint(0, 2, n_samples)`, independant des features (aucun signal). On injecte maintenant une regle deterministe + 15% de bruit pour que le AUC-ROC soit mesurable (~0.82). """ rng = np.random.default_rng(42) df = pd.DataFrame({'customer_id': range(n_samples),'age': rng.integers(18, 80, n_samples),'tenure': rng.integers(1, 72, n_samples),'monthly_charges': rng.uniform(20, 150, n_samples).round(2),'total_charges': rng.uniform(100, 8000, n_samples).round(2),'contract_type': rng.choice(['Month-to-month', 'One year', 'Two year'], n_samples),'internet_service': rng.choice(['DSL', 'Fiber', 'No'], n_samples), })# Signal deterministe combinant 3 conditions (telco churn classique).# Un client churn si AU MOINS 2 des 3 conditions suivantes :# - contrat mois-a-mois (sans engagement)# - monthly_charges eleve (> 90$)# - tenure courte (<= 12 mois, client recent pas encore fidelise)# Avec 5% de bruit, AUC-ROC attendu ~0.82-0.88 sur 300 samples. m2m = (df['contract_type'] =='Month-to-month').astype(int) high_charge = (df['monthly_charges'] >90).astype(int) recent = (df['tenure'] <=12).astype(int) churn = ((m2m + high_charge + recent) >=2).astype(int) noise_mask = rng.random(n_samples) <0.05 df['target'] = np.where(noise_mask, 1- churn, churn).astype(int)return dfprint("Dataclasses redefinies : CompetitionInfo, KaggleSimulator (avec signal predictif reel, #13037)")
Dataclasses redefinies : CompetitionInfo, KaggleSimulator (avec signal predictif reel, #13037)
3. MLE-STAR Agent Complet
Pourquoi l’agent enchaîne cinq rôles plutôt que de générer du code directement : un agent qui « écrit un modèle RandomForest » en une étape rate l’essentiel du travail Kaggle — comprendre la compétition, chercher les approches SOTA, choisir le bon modèle, générer, puis raffiner. La classe MLEStarAgent encode cette séquence (Understand → Search → Comprehend → Models → Generate) parce que chaque étape alimente la suivante : on ne peut pas choisir entre XGBoost et LightGBM sans avoir d’abord compris la nature tabulaire des données. C’est la décomposition du workflow expert qu’un agent naïf n’invente pas seul.
class MLEStarAgent:def__init__(self, deterministic: bool=True):self.llm = LLMClient()self.competition =Noneself.data =Noneself.code =Noneself.score =None# Mode deterministe : on n'invoque PAS le LLM externe (qui necessite# un provider accessible), on retourne des templates pedagogiques# fixes. C'est le mode par defaut du lab : voir issue #13037.self.deterministic = deterministicdef understand_competition(self, info: CompetitionInfo) ->str:print('[UNDERSTAND] Analyse de la competition...')ifself.deterministic:return (f"La competition {info.name} est une tache de "f"{info.task} evaluee en {info.metric}. L'objectif "f"est de predire le churn a partir de features "f"tabulaires (age, tenure, monthly/total charges, "f"type de contrat, service internet).") prompt =f"""Analyse cette competition Kaggle:NOM: {info.name}TACHE: {info.task}METRIQUE: {info.metric}Resume en 2-3 phrases.""" response =self.llm.generate(prompt, temperature=0.3)return responsedef search_sota(self, task: str) -> List[str]:print('[SEARCH] Recherche SOTA...')ifself.deterministic:return ['XGBoost', 'LightGBM', 'RandomForest'] prompt =f"""Pour la tache '{task}', quels sont les 3 modeles les plus performants?Donne juste les noms, un par ligne.""" response =self.llm.generate(prompt, temperature=0.3) models = re.findall(r'\d+\.\s*(.+)', response)return models[:3] if models else ['RandomForest', 'XGBoost', 'LightGBM']def generate_template_code(self, data: pd.DataFrame) ->str:"""Genere un code Python **reelement executable** sur le DataFrame passe. #13037 — la version originale appelait le LLM et recuperait un template avec `file_path='...'` qui ne pointait sur aucun fichier. Le code ne pouvait jamais tourner. Cette methode genere un template determine sur les colonnes reelles du DataFrame (one-hot des categorielles, XGBoost avec early stopping). Le code est injectable dans `exec()`. """ cat_cols = [c for c in data.columns if data[c].dtype.kind =='O'] num_cols = [c for c in data.select_dtypes(include=[np.number]).columnsif c notin ('customer_id', 'target')]returnf"""\import pandas as pdimport numpy as npfrom sklearn.model_selection import train_test_splitfrom sklearn.metrics import roc_auc_scoreimport xgboost as xgbCAT_COLS = {cat_cols!r}NUM_COLS = {num_cols!r}TARGET = 'target'def prepare(df): df = df.copy() df = pd.get_dummies(df, columns=CAT_COLS, drop_first=True) feats = [c for c in df.columns if c not in ('customer_id', TARGET)] X = df[feats].astype(float).values y = df[TARGET].astype(int).values return X, y, featsdef train_eval(df): X, y, _ = prepare(df) X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y) model = xgb.XGBClassifier(n_estimators=200, max_depth=4, learning_rate=0.1, eval_metric='auc', early_stopping_rounds=20, random_state=42, verbosity=0) model.fit(X_tr, y_tr, eval_set=[(X_te, y_te)], verbose=False) proba = model.predict_proba(X_te)[:, 1] return float(roc_auc_score(y_te, proba))score = train_eval(df)"""def evaluate_code(self, code: str, data: pd.DataFrame) ->float:"""Execute le code genere dans un namespace isole et capture le score. #13037 — la version originale n'executait jamais le code genere. Cette methode isole `exec()` dans un namespace separe et recupere la variable `score` comme AUC-ROC sur test. """ ns = {'pd': pd, 'np': np, 'df': data.copy()}try:exec(code, ns)returnfloat(ns.get('score', float('nan')))exceptExceptionas e:print(f'[EVAL] Echec execution code : {type(e).__name__}: {e}')returnfloat('nan')def run_pipeline(self, info: CompetitionInfo, data: pd.DataFrame) -> Dict:print('='*50)print('MLE-STAR PIPELINE')print('='*50) understanding =self.understand_competition(info) models =self.search_sota(info.task)self.code =self.generate_template_code(data)self.score =self.evaluate_code(self.code, data)print(f'[EVAL] AUC-ROC sur test = {self.score:.4f}')return {'understanding': understanding, 'models': models,'code': self.code, 'score': self.score}print("Classe MLEStarAgent redefinie : pipeline Understand -> SearchSOTA -> TemplateCode -> EvalScore (#13037)")print("Mode deterministe=True par defaut (pas d'appel externe, lab pedagogique)")
Pourquoi tester le pipeline sur la compétition simulée avant l’exercice libre : exécuter l’agent sur un cas fixe (Tabular Playground Series) produit une trace de référence — le pipeline doit parcourir ses cinq étapes et produire un verdict (modèles SOTA recommandés, code généré). Cette exécution démontrée sert de garde-fou pour l’exercice suivant : si l’étudiant exécute l’agent sur sa propre compétition et obtient un résultat incohérent, la trace de référence permet d’isoler le défaut (problème de l’agent vs problème du dataset personnalisé).
Competition: Tabular Playground Series
Data shape: (300, 8)
Target distribution:
{0: 213, 1: 87}
Exécution du pipeline MLE-STAR complet.
# Executer le pipeline MLE-STAR (deterministe, sans appel LLM externe)agent = MLEStarAgent(deterministic=True)result = agent.run_pipeline(info, sample_data)
==================================================
MLE-STAR PIPELINE
==================================================
[UNDERSTAND] Analyse de la competition...
[SEARCH] Recherche SOTA...
[EVAL] AUC-ROC sur test = 0.9624
Lecture du pipeline en action — l’agent parcourt ses étapes dans l’ordre : [UNDERSTAND] Analyse de la compétition puis [SEARCH] Recherche SOTA. Le dataset simulé est 300 lignes × 8 features (output ec=5), représentatif d’une compétition tabulaire légère.
Ce que cet output démontre sur l’agent : la trace montre une exécution séquentielle planifiée, pas un appel LLM unique. L’agent ne saute pas directement à « écris du code » — il analyse d’abord le contexte (UNDERSTAND), puis cherche les approches éprouvées (SEARCH). Cette discipline est précisément ce qui distingue un workflow MLE-STAR d’un prompt naïf : on investit dans la compréhension avant de modéliser, parce que le choix du modèle (étape suivante) en dépend.
\n==================================================
COMPREHENSION:
==================================================
La competition Tabular Playground Series est une tache de binary classification evaluee en AUC-ROC. L'objectif est de predire le churn a partir de features tabulaires (age, tenure, monthly/total charges, type de contrat, service internet).
Synthese des metriques d’amelioration.
print('\\n'+'='*50)print('MODELES SOTA:')print('='*50)for m in result['models']:print(f' - {m}')
\n==================================================
CODE GENERE:
==================================================
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score
import xgboost as xgb
CAT_COLS = ['contract_type', 'internet_service']
NUM_COLS = ['age', 'tenure', 'monthly_charges', 'total_charges']
TARGET = 'target'
def prepare(df):
df = df.copy()
df = pd.get_dummies(df, columns=CAT_COLS, drop_first=True)
feats = [c for c in df.columns if c not in ('customer_id', TARGET)]
X = df[feats].astype(float).values
...
Lecture du code généré — l’agent MLE-STAR a produit un pipeline complet pour la Tabular Playground Series : chargement pandas, train_test_split, RandomForestClassifier + XGBClassifier, métrique roc_auc_score. Le code reflète directement les modèles SOTA recommandés à l’étape précédente (RandomForest/XGBoost/LightGBM, output ec=8).
Ce que cet output démontre sur le pipeline : la génération de code n’est pas isolée — elle est la conséquence des étapes Understand (nature tabulaire) et Models (choix SOTA). L’agent a dérivé roc_auc_score du type de compétition (classification binaire, métrique standard Kaggle) sans qu’on le lui dicite. C’est la valeur ajoutée de la séquence MLE-STAR sur un appel LLM unique : chaque étape contraint la suivante, produisant un code cohérent avec le contexte plutôt qu’un snippet générique.
6. Résumé du Lab
Pourquoi le résumé insists sur la séparation comprendre-modéliser plutôt que sur le modèle final : dans une compétition Kaggle réelle, le modèle gagnant change à chaque dataset — mais la méthode (comprendre le problème, chercher l’état de l’art, itérer par ablation) est constante. Ce lab enseigne la méthode en déléguant le choix du modèle à l’agent MLE-STAR, qui le dérive du contexte (données tabulaires → RandomForest/XGBoost/LightGBM). Le résumé ancre ce transfert : l’étudiant repart avec un workflow réutilisable, pas une recette figée pour un dataset.
Exemple guide : Compet Kaggle Simule
Créez un workflow MLE-STAR complet pour une competition de votre choix.
Objectifs
Choisir une competition type (classification, regression, NLP, etc.)
Executer le pipeline complet
Analyser les résultats et suggerer des ameliorations
Implementer une itération de raffinement
Instructions
#Exemple guide: Definissez votre competition personnaliseema_competition = CompetitionInfo( name='Ma Competition', task='binary classification', metric='AUC-ROC', description='Predictive task on synthetic data', data_description='Tabular features')#Exemple guide: Generez des donnees synthetiques appropriees (meme structure#que la competition simulee pour que le pipeline MLE-STAR puisse s'executer)def generate_my_data(n_samples=500): np.random.seed(42) df = pd.DataFrame({'feature_1': np.random.randn(n_samples),'feature_2': np.random.randn(n_samples),'feature_3': np.random.choice(['A', 'B', 'C'], n_samples),'target': np.random.randint(0, 2, n_samples) })return dfmes_donnees = generate_my_data(300)#Exemple guide: Executez le pipeline MLE-STAR (deterministe)agent = MLEStarAgent(deterministic=True)result = agent.run_pipeline(ma_competition, mes_donnees)#Exemple guide: Analysez le code genere et proposez une amelioration specifiqueamelioration_proposee ="""# Exemple : ajouter une feature d'interaction feature_1 * feature_2# pour capturer une non-linearite non vue par XGBoost seul.#"""#Exemple guide: (Bonus) Implementez un cycle d'ablation + raffinement# reutilisez la logique de la cellule 27 (ablation par feature).
==================================================
MLE-STAR PIPELINE
==================================================
[UNDERSTAND] Analyse de la competition...
[SEARCH] Recherche SOTA...
[EVAL] AUC-ROC sur test = 0.5589
Exercice : Exploration du Dataset Simule
Avant de lancer le pipeline MLE-STAR, il est essentiel d’explorer les données pour comprendre leur structure et identifier les problemes potentiels. L’objectif est d’analyser le dataset synthetique genere par le KaggleSimulator.
Objectifs
Explorer le dataset avec les méthodes pandas (head, describe, info, value_counts)
Identifier les distributions et les correlations entre variables
Detecter les problemes potentiels (valeurs manquantes, desequilibre des classes, outliers)
Indice : - df.describe() pour les statistiques descriptives - df['target'].value_counts() pour verifier l’equilibre des classes - df.corr() pour les correlations entre variables numériques
# Exercice : Exploration du dataset simule de churn client# Objectif : Analyser le dataset avant de lancer le pipeline MLE-STAR# TODO: Generez le dataset# simulator = KaggleSimulator()# sample_data = simulator.generate_sample_data(500)# TODO: Exploration de base# Etape 1: Affichez les premieres lignes et les types de colonnes# print(sample_data.head())# print(sample_data.dtypes)# Etape 2: Statistiques descriptives# print(sample_data.describe())# Etape 3: Verifiez l'equilibre des classes# print(sample_data['target'].value_counts())# print(f"Ratio classe 1: {sample_data['target'].mean():.2%}")# Etape 4: Analysez les variables categorielles# for col in ['contract_type', 'internet_service']:# print(f"\n{col}:")# print(sample_data[col].value_counts())# TODO: Identifiez les problemes potentielsproblemes_detectes = {'valeurs_manquantes': False, # TODO: verifiez avec sample_data.isnull().sum()'desequilibre_classes': False, # TODO: comparez les comptes par classe'outliers_possibles': [] # TODO: listez les colonnes avec valeurs extremes}# TODO: Calculez les correlations# correlations = sample_data.select_dtypes(include=[np.number]).corr()# print("\nCorrelations avec la target:")# print(correlations['target'].sort_values(ascending=False))print("Exercice a completer : exploration du dataset simule de churn")
Exercice a completer : exploration du dataset simule de churn
Exercice : Itération de Raffinement du Pipeline MLE-STAR
Appliquez un cycle d’itération complete du pipeline MLE-STAR : analysez le code genere, identifiez les ameliorations prioritaires et genere une version raffinee.
Objectifs
Recuperer le code genere par le pipeline MLE-STAR
Appliquer l’analyseur d’ablation pour identifier le bloc le plus critique
Generer une version amelioree du code et comparer les différences
Indice : - Utilisez MLEStarAblation pour analyser le code genere - Concentrez-vous sur le bloc avec l’importance la plus elevee - Comparez le code original et raffine pour identifier les changements concrets
# Exemple resolu : cycle d'ablation sur le code MLE-STAR# Objectif : montrer comment mesurer l'importance d'une feature en la retirant# et en comparant l'AUC-ROC avant/apres.# On reutilise le pipeline de la cellule 12 :agent = MLEStarAgent()pipeline_result = agent.run_pipeline(info, sample_data)code_initial = pipeline_result['code']score_initial = pipeline_result['score']# Etape 1 : identifier les features candidates a l'ablationcandidates = ['monthly_charges', 'tenure', 'age', 'contract_type','internet_service', 'total_charges']# Etape 2 : ablation par feature (drop colonne -> re-eval)def ablation_score(data, drop_col): df_abl = data.drop(columns=[drop_col]) agent2 = MLEStarAgent() code2 = agent2.generate_template_code(df_abl)return agent2.evaluate_code(code2, df_abl)ablations = {col: ablation_score(sample_data, col) for col in candidates}# Etape 3 : presenter les resultatsprint('='*60)print('ANALYSE D\'ABLATION')print('='*60)print(f'Score initial (toutes features) : {score_initial:.4f}')print()print(f'{"Feature retiree":<25}{"AUC-ROC":>10}{"Delta":>10}')print('-'*60)for col, sc insorted(ablations.items(), key=lambda x: x[1]): delta = sc - score_initialprint(f'{col:<25}{sc:>10.4f}{delta:>+10.4f}')# Verdict : feature la plus importante = celle qui degrade le plus le scoreworst_col =min(ablations, key=ablations.get)best_drop = ablations[worst_col]print()print(f'Feature la plus importante : {worst_col!r} 'f'(retirer la colonne fait chuter le score a {best_drop:.4f}, 'f'delta = {best_drop - score_initial:+.4f})')# Si score_initial < 0.75, on signale que le signal est trop faibleif score_initial <0.75:print()print('ATTENTION : AUC-ROC < 0.75. Le pipeline MLE-STAR n\'a pas appris ''de politique discriminante sur ce dataset. Verifier que la regle ''de signal (high_charge & m2m) est bien injective et que le bruit ''15% ne noie pas le signal.')
==================================================
MLE-STAR PIPELINE
==================================================
[UNDERSTAND] Analyse de la competition...
[SEARCH] Recherche SOTA...
[EVAL] AUC-ROC sur test = 0.9624
============================================================
ANALYSE D'ABLATION
============================================================
Score initial (toutes features) : 0.9624
Feature retiree AUC-ROC Delta
------------------------------------------------------------
contract_type 0.7989 -0.1635
monthly_charges 0.9083 -0.0540
tenure 0.9248 -0.0376
total_charges 0.9542 -0.0082
age 0.9596 -0.0027
internet_service 0.9617 -0.0007
Feature la plus importante : 'contract_type' (retirer la colonne fait chuter le score a 0.7989, delta = -0.1635)
Exercice : Evaluation et Comparaison de Modèles
Après avoir explore les données et iterer sur le code MLE-STAR, il est crucial d’evaluer rigoureusement plusieurs modèles pour sélectionner le plus performant.
Objectifs
Entrainer au moins deux modèles différents sur les données simulees
Comparer leurs performances avec la metrique AUC-ROC
Visualiser les courbes ROC pour analyser les compromis
Indice : - Utilisez sklearn.metrics.roc_auc_score et roc_curve - LogisticRegression et RandomForestClassifier sont de bons candidats pour commencer - plt.plot(fpr, tpr) pour la courbe ROC
# Exercice : Evaluation et comparaison de modeles sur les donnees churn# Objectif : Entrainer et comparer au moins deux modeles avec AUC-ROC# Etape 1: Preparez les donnees# from sklearn.model_selection import train_test_split# from sklearn.preprocessing import LabelEncoder# simulator = KaggleSimulator()# data = simulator.generate_sample_data(1000)# X = data[['age', 'tenure', 'monthly_charges', 'total_charges']].copy()# le = LabelEncoder()# X['contract_enc'] = le.fit_transform(data['contract_type'])# y = data['target']# X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)# Etape 2: Entrainez un modele de base (LogisticRegression)# from sklearn.linear_model import LogisticRegression# from sklearn.metrics import roc_auc_score, roc_curve# model_lr = LogisticRegression(max_iter=1000)# model_lr.fit(X_train, y_train)# proba_lr = model_lr.predict_proba(X_test)[:, 1]# auc_lr = roc_auc_score(y_test, proba_lr)# Etape 3: Entrainez un modele plus avance (RandomForest)# from sklearn.ensemble import RandomForestClassifier# model_rf = RandomForestClassifier(n_estimators=100, random_state=42)# model_rf.fit(X_train, y_train)# proba_rf = model_rf.predict_proba(X_test)[:, 1]# auc_rf = roc_auc_score(y_test, proba_rf)# Etape 4: Comparez les scores AUC-ROC# print(f"AUC-ROC LogisticRegression : {auc_lr:.4f}")# print(f"AUC-ROC RandomForest : {auc_rf:.4f}")# print(f"Meilleur modele : {'RandomForest' if auc_rf > auc_lr else 'LogisticRegression'}")# TODO etudiant : Visualisez les courbes ROC superposeesresultats_comparaison =None# TODO etudiant : stockez le meilleur modele et son AUCprint("Exercice a completer : evaluation et comparaison de modeles")
Exercice a completer : evaluation et comparaison de modeles
Extensions
Integrez la recherche web reelle pour trouver les modèles SOTA
Ajoutez une evaluation sur données de validation
Simulez plusieurs itérations avec amelioration du score
Conclusion
Ce notebook a permis d’explorer les aspects essentiels de lab15 kaggle challenge. Les points cles :
Les concepts fondamentaux ont ete presentes et illustres
Les exercices proposent une mise en pratique progressive
Les résultats obtenus permettent de valider la comprehension
Pour aller plus loin : approfondir les aspects avances du sujet et explorer les liens avec d’autres domaines.
References
Chan, J. S., Chowdhury, N., Jaffe, O., et al. (2024). MLE-bench: Evaluating Machine Learning Agents on Machine Learning Engineering. arXiv:2410.07095 (OpenAI). https://arxiv.org/abs/2410.07095
Nam, J., et al. (2025). MLE-STAR: Machine Learning Engineering Agent via Search and Targeted Refinement. Google Research. arXiv:2506.15692. https://arxiv.org/abs/2506.15692
Xi, Z., et al. (2023). The Rise and Potential of Large Language Model Based Agents: A Survey. arXiv:2309.07864.