Aller au contenu
English

Les arbres de décision

  • Leçon 15
  • 55 min
  • Module 5 : Essayer d'autres familles de modèles
Leçon 15 sur 27 · Apprentissage automatique : du problème à un modèle fiableLes arbres de décision

Ce que vous saurez faire

La régression logistique est une famille de modèles. L’arbre de décision en est une autre : il attribue un score à un billet de soutien par des questions successives. Découvrez comment un arbre choisit ses questions. Essayez-le sur les billets de Larkfield avec le même test équitable qu’avant. Ajoutez ensuite le résultat à votre journal d’expériences.

Carnet JupyterFaites cette leçon dans un carnet JupyterColab · Kaggle · GitHub · en anglais

Le carnet (notebook) Jupyter contient toutes les cellules de code, tâches et vérifications de cette leçon, avec les consignes. Ses cellules de configuration installent les paquets, téléchargent les données de pratique et créent ticket_model.py. Elles créent aussi le journal d’expériences de la leçon précédente. Le carnet fonctionne donc sans le projet local.

Le carnet est en anglais. Colab et Kaggle ouvrent votre propre copie. Il faut un compte Google ou Kaggle gratuit. Vous êtes bloqué ? Consultez le carnet de solution.

Avant de commencerCe qu’il faut savoir et avoir sous la mainEnviron 55 minutes

Ce que vous devez savoir

Ce qu’il vous faut sur votre ordinateur (seulement pour le parcours local; le carnet n’en a pas besoin)

Testé sur macOS avec Python 3.14.6, pandas 3.0.6 et scikit-learn 1.9.1. Les étapes pour Windows et Linux n’ont pas été testées. Le carnet a été testé dans Jupyter.

Au jeu des vingt questions, une personne pense à une chose. L’autre doit la trouver avec des questions auxquelles on répond par oui ou non. Une bonne joueuse ne commence pas par « Est-ce mon chat? ». Elle commence par une question qui sépare bien les possibilités, comme « Est-ce vivant? ». Chaque réponse l’envoie sur un chemin différent. La question suivante dépend des réponses précédentes.

Une infirmière à l’entrée d’un hôpital travaille de façon semblable. Elle suit une courte liste de vérification : « Le patient respire-t-il normalement? Y a-t-il un saignement important? La douleur est-elle intense? ». Un « non » à la première question mène directement au groupe le plus urgent. L’ordre des questions compte, et chaque réponse réduit le groupe.

Un modèle peut aussi fonctionner ainsi. Au lieu d’additionner des faits pondérés, il pose des questions sur le billet, une à la fois, dans un ordre fixe.

La régression logistique donne un poids à chaque caractéristique, puis additionne les caractéristiques pondérées. Un long message ajoute le même risque à chaque billet, quelle que soit sa priorité. C’est une hypothèse forte. Un long message compte peut-être beaucoup pour un billet de priorité 1, mais peu pour un billet de priorité 3. Quand l’effet d’un fait dépend d’un autre, les deux faits interagissent. La régression logistique ne peut apprendre une interaction que si quelqu’un crée une colonne spéciale pour celle-ci.

Un modèle fondé sur des questions n’a pas cette limite. Si la première question est « La priorité est-elle 1? », la question suivante se pose séparément dans chaque groupe. Il peut donc utiliser un seuil de nombre de mots pour les billets de priorité 1, et un autre pour les autres billets.

Ce modèle est un arbre de décision. Il porte ce nom parce que son schéma ressemble à un arbre dessiné à l’envers. La première question est la racine, en haut, et les réponses sont les branches. Les groupes aux extrémités sont les feuilles. Voici trois autres mots :

  • Une division est une question et les deux groupes qu’elle crée.
  • La profondeur est le nombre de questions entre la racine et une feuille.
  • Le score de l’arbre pour un billet est la proportion de billets d’entraînement transférés au niveau supérieur dans sa feuille.

Voici 10 billets fictifs, assez peu nombreux pour les vérifier à la main. Quatre ont été transférés au niveau supérieur.

Billet T-01 T-02 T-03 T-04 T-05 T-06 T-07 T-08 T-09 T-10
priority 1 1 1 1 2 2 2 3 3 3
word_count 150 40 120 45 130 160 20 30 145 60
escalated 1 0 1 1 1 0 0 0 0 0
import pandas as pd
from sklearn.metrics import average_precision_score
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.tree import DecisionTreeClassifier, export_text
from ticket_model import FEATURES, TARGET, build_pipeline, load
train = load("train")
tiny = pd.DataFrame({
"ticket": [f"T-{i:02d}" for i in range(1, 11)],
"priority": [1, 1, 1, 1, 2, 2, 2, 3, 3, 3],
"word_count": [150, 40, 120, 45, 130, 160, 20, 30, 145, 60],
"escalated": [1, 0, 1, 1, 1, 0, 0, 0, 0, 0],
})

Comme la bonne joueuse des vingt questions, l’arbre veut une première question qui sépare bien les billets. Les meilleurs groupes possibles sont purs : tous transférés au niveau supérieur, ou aucun. L’impureté mesure à quel point un groupe est mélangé.

L’arbre utilise l’impureté de Gini. Prenez p, la proportion de billets transférés au niveau supérieur dans un groupe. L’impureté vaut 2 × p × (1 − p). Un groupe pur a p = 0 ou p = 1, donc son impureté vaut 0. Un groupe moitié-moitié donne 2 × 0,5 × 0,5 = 0,5 : c’est le plus mélangé.

Faites le calcul pour les 10 billets. Quatre sur dix ont été transférés, donc p = 0,4, et l’impureté vaut 2 × 0,4 × 0,6 = 0,48. Comparez maintenant deux questions possibles. Après une division, l’arbre pondère l’impureté de chaque groupe selon sa taille :

Question Groupe oui Groupe non Impureté après la division
priority = 1? 4 billets, 3 transférés : 2 × 0,75 × 0,25 = 0,375 6 billets, 1 transféré : 2 × 1/6 × 5/6 = 0,278 (4 × 0,375 + 6 × 0,278) ÷ 10 = 0,317
plus de 100 mots? 5 billets, 3 transférés : 0,48 5 billets, 1 transféré : 0,32 (5 × 0,48 + 5 × 0,32) ÷ 10 = 0,40

« priority = 1? » réduit davantage l’impureté, de 0,48 à 0,317. L’arbre essaie toutes les questions possibles sur chaque caractéristique. Il choisit celle qui donne la plus faible impureté après la division. Il fait ensuite la même chose dans chaque groupe, jusqu’à atteindre sa profondeur maximale ou obtenir des groupes purs.

Vérifiez cela avec scikit-learn. DecisionTreeClassifier(max_depth=2) construit un arbre avec au plus deux questions sur chaque chemin. export_text affiche ses questions. Les deux dernières lignes attribuent un score à un nouveau billet de priorité 2 avec 140 mots :

tiny_tree = DecisionTreeClassifier(max_depth=2, random_state=0)
tiny_tree.fit(tiny[["priority", "word_count"]], tiny["escalated"])
print(export_text(tiny_tree, feature_names=["priority", "word_count"], show_weights=True))
new_ticket = pd.DataFrame({"priority": [2], "word_count": [140]})
print("score of the new ticket:", tiny_tree.predict_proba(new_ticket)[0, 1].round(3))

La sortie :

Sortie
|--- priority <= 1.50
| |--- word_count <= 42.50
| | |--- weights: [1.00, 0.00] class: 0
| |--- word_count > 42.50
| | |--- weights: [0.00, 3.00] class: 1
|--- priority > 1.50
| |--- word_count <= 95.00
| | |--- weights: [3.00, 0.00] class: 0
| |--- word_count > 95.00
| | |--- weights: [2.00, 1.00] class: 0
score of the new ticket: 0.333

La première question est « priority = 1? », écrite priority <= 1.50 (priorité inférieure ou égale à 1,50). L’arbre place son seuil à mi-chemin entre deux valeurs. weights: [2.00, 1.00] signifie que cette feuille contient 2 billets non transférés et 1 billet transféré. Remarquez l’interaction : la deuxième question utilise 42,5 mots du côté priorité 1 et 95 mots de l’autre côté. La régression logistique ne pourrait pas faire cela avec un seul poids pour word_count.

L'arbre de profondeur 2 sur les 10 billets. La racine demande priority = 1? (10 billets, 4 transférés, impureté 0,48). Oui : T-01 à T-04, 3 sur 4 transférés, puis la question plus de 42 mots; non mène à une feuille avec T-02, score 0,0; oui mène à une feuille avec T-01, T-03 et T-04, score 1,0. Non : T-05 à T-10, 1 sur 6 transféré, puis la question plus de 95 mots; non mène à une feuille avec T-07, T-08 et T-10, score 0,0; oui mène à une feuille avec T-05, T-06 et T-09, score 0,333.
L'arbre sur les 10 billets. Chaque billet suit les réponses jusqu'à une feuille. Trois feuilles sont pures; la dernière mélange T-05 (transféré) avec T-06 et T-09.
Description textuelle du diagramme

La racine demande « priority = 1? » aux 10 billets, dont 4 ont été transférés, avec une impureté de 0,48.

  • Oui : T-01 à T-04, 3 sur 4 transférés. La question suivante est « plus de 42 mots? ». Non : une feuille avec T-02 seulement, score 0,0. Oui : une feuille avec T-01, T-03 et T-04, score 1,0.
  • Non : T-05 à T-10, 1 sur 6 transféré. La question suivante est « plus de 95 mots? ». Non : une feuille avec T-07, T-08 et T-10, score 0,0. Oui : une feuille avec T-05, T-06 et T-09, score 0,333.

Un nouveau billet de priorité 2 avec 140 mots suit « non », puis « oui », et arrive dans la dernière feuille. Son score vaut 1 ÷ 3 = 0,333.

Faites maintenant la même chose sur les 16 939 billets d’entraînement, avec les 10 caractéristiques. Un changement vient d’abord : un arbre n’a pas besoin de l’étape de mise à l’échelle du pipeline. Un arbre compare une caractéristique à un seuil. La mise à l’échelle change les nombres, mais pas leur ordre. Chaque billet reste donc du même côté de chaque seuil. tree_pipeline() retire l’étape de mise à l’échelle de build_pipeline() ("passthrough" signifie « aucune étape ici ») :

def tree_pipeline(model):
"""build_pipeline() without the scaler: a tree does not need it."""
return build_pipeline(model).set_params(prepare__numbers__scale="passthrough")
pipeline = tree_pipeline(DecisionTreeClassifier(max_depth=2, random_state=0))
pipeline.fit(train[FEATURES], train[TARGET])
names = list(pipeline.named_steps["prepare"].get_feature_names_out())
print(export_text(pipeline.named_steps["model"], feature_names=names, show_weights=True))

La sortie (le préfixe numbers__ est le nom de la branche du pipeline pour les variables numériques) :

Sortie
|--- numbers__priority <= 1.50
| |--- numbers__word_count <= 66.50
| | |--- weights: [635.00, 128.00] class: 0
| |--- numbers__word_count > 66.50
| | |--- weights: [1057.00, 565.00] class: 0
|--- numbers__priority > 1.50
| |--- numbers__word_count <= 100.50
| | |--- weights: [7954.00, 507.00] class: 0
| |--- numbers__word_count > 100.50
| | |--- weights: [5310.00, 783.00] class: 0
Un arbre de décision de profondeur 2 entraîné sur les 16 939 billets d'entraînement. La première question est priority = 1. Oui : 2 385 billets, 29,1 % transférés, puis la question plus de 66 mots; non mène à la feuille 1 avec un score de 0,168 (763 billets, 128 transférés), oui mène à la feuille 2 avec un score de 0,348 (1 622 billets, 565 transférés). Non : 14 554 billets, 8,9 % transférés, puis la question plus de 100 mots; non mène à la feuille 3 avec un score de 0,060 (8 461 billets, 507 transférés), oui mène à la feuille 4 avec un score de 0,129 (6 093 billets, 783 transférés).
L'arbre réel de profondeur 2, entraîné sur les données d'entraînement. Le score de chaque feuille est sa proportion de billets d'entraînement transférés au niveau supérieur.
Description textuelle du diagramme

L’arbre commence avec les 16 939 billets d’entraînement, dont 11,7 % ont été transférés, et demande « priority = 1? ».

  • Oui : 2 385 billets, 29,1 % transférés. La question suivante est « plus de 66 mots? ». Non : feuille 1, 763 billets, 128 transférés, score 0,168. Oui : feuille 2, 1 622 billets, 565 transférés, score 0,348.
  • Non (priorité 2 ou 3) : 14 554 billets, 8,9 % transférés. La question suivante est « plus de 100 mots? ». Non : feuille 3, 8 461 billets, 507 transférés, score 0,060. Oui : feuille 4, 6 093 billets, 783 transférés, score 0,129.

L’arbre a trouvé deux faits par lui-même : la priorité et la longueur du premier message. Un billet de priorité 1 avec plus de 66 mots présente le plus grand risque. Sur 1 622 billets, 565 ont été transférés, pour un score de 0,348. Un billet court de priorité 2 ou 3 présente le moins de risque, à 0,060. Les poids se lisent [non transférés, transférés]. Pour la feuille 2 : 1 057 + 565 = 1 622 billets, et 565 ÷ 1 622 = 0,348. Les quatre feuilles totalisent 16 939 billets, soit tous les billets d’entraînement.

Vous pouvez expliquer cet arbre à Grace en une minute, et elle peut le comparer à son expérience. C’est une vraie force. Mais il ne donne que quatre scores différents, donc son classement des billets manque de finesse. Un arbre plus profond a plus de feuilles et plus de scores différents. Un arbre plus profond est-il meilleur? Seul un test équitable peut le dire.

La comparaison suit les règles de la boucle : les mêmes 5 plis d’entraînement, la même métrique et le résultat dans le journal. Deux courts rappels :

  • La validation croisée divise les données d’entraînement en 5 plis. Elle entraîne le modèle 5 fois, chaque fois sur 4 plis, puis l’évalue sur le pli qu’il n’a pas vu. La moyenne des 5 scores est le score de validation croisée (CV). Leur écart-type montre à quel point il varie par hasard. Données d’entraînement, de validation et de test l’explique en détail.
  • La précision moyenne (AP) trie les billets par score et mesure à quel point les billets transférés arrivent tôt. Un même score pour tous les billets donne le taux de transfert, 0,117. Le compromis entre précision et rappel l’explique en détail.

evaluate() renvoie deux nombres pour un pipeline. L’AP d’entraînement entraîne le modèle sur tous les billets d’entraînement et évalue ces mêmes billets. L’AP de validation croisée est le score équitable, avec son écart-type. table() affiche les résultats, une ligne par modèle.

cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=0)
def evaluate(pipeline):
"""Train AP (fit on all train tickets) and CV AP (mean ± std of the 5 folds)."""
fold_scores = cross_val_score(pipeline, train[FEATURES], train[TARGET], cv=cv, scoring="average_precision")
pipeline.fit(train[FEATURES], train[TARGET])
train_ap = average_precision_score(train[TARGET], pipeline.predict_proba(train[FEATURES])[:, 1])
return {"train AP": round(float(train_ap), 3), "CV AP": round(float(fold_scores.mean()), 3),
"std": round(float(fold_scores.std()), 3)}
def table(results):
"""The results as a table, one row per model (rows still set to ... are left out)."""
return pd.DataFrame({name: r for name, r in results.items() if isinstance(r, dict)}).T
results = {
"logistic regression": evaluate(build_pipeline()),
"tree, depth 3": evaluate(tree_pipeline(DecisionTreeClassifier(max_depth=3, random_state=0))),
"tree, depth 6": evaluate(tree_pipeline(DecisionTreeClassifier(max_depth=6, random_state=0))),
"tree, no limit": evaluate(tree_pipeline(DecisionTreeClassifier(random_state=0))),
}
print(table(results))

Avant de lire la sortie, faites une prédiction : quel arbre a la plus grande AP d’entraînement? Lequel a la plus grande AP de validation croisée?

Sortie
train AP CV AP std
logistic regression 0.328 0.327 0.012
tree, depth 3 0.244 0.234 0.011
tree, depth 6 0.346 0.258 0.010
tree, no limit 1.000 0.137 0.004

Lisez le tableau une ligne à la fois :

  • La régression logistique a presque la même AP d’entraînement et de validation croisée : 0,328 et 0,327. Ce qu’elle a appris sur certains billets fonctionne sur d’autres.
  • L’arbre de profondeur 3 est bien en dessous : 0,234. Trois questions ne suffisent pas à bien séparer les billets.
  • L’arbre de profondeur 6 est le meilleur arbre, à 0,258, mais reste 0,069 sous la régression logistique. Cela représente plus de cinq écarts-types : une vraie différence.
  • L’arbre sans limite obtient un score parfait de 1,000 à l’entraînement et la pire AP de validation croisée, 0,137. C’est près du plancher de 0,117. Il a continué à poser des questions jusqu’à ce que chaque feuille soit pure. Il a donc mémorisé chaque billet d’entraînement, y compris les détails dus au hasard. C’est le modèle qui mémorise dans Données d’entraînement, de validation et de test : parfait sur les exercices de pratique, presque inutile sur les nouveaux.

Pourquoi l’arbre perd-il? Les arbres peuvent trouver des interactions, mais ces données en ont peu de fortes. La plupart du risque vient de faits qui ajoutent ou retirent chacun un peu de risque indépendamment des autres. C’est exactement la forme de la régression logistique. Un arbre doit décrire une telle variation progressive par paliers, une feuille à la fois. Il lui faut beaucoup de feuilles et de billets pour y arriver.

Ajoutez les trois arbres à votre journal d’expériences. Faites-le dans le carnet. Chaque étape comporte une vérification.

  1. Exécutez la cellule avec evaluate(). Vous devriez voir le tableau ci-dessus.
  2. Écrivez la ligne E06 pour l’arbre de profondeur 3. Prenez les nombres du tableau : results["tree, depth 3"]["CV AP"] et results["tree, depth 3"]["std"]. Laissez l’AP de validation vide (None). Écrivez "reject" (rejeter) et une raison.
  3. Écrivez les lignes E07 (profondeur 6) et E08 (sans limite) de la même façon.
  4. Exécutez show_log(). Vous devriez voir huit lignes.
  5. Exécutez la cellule de vérification. Vous devriez voir Check passed: the log from E06 to E08 is right. (Vérification réussie : le journal de E06 à E08 est correct.)
Afficher un exemple de réponse
for row_id, name, change, reason in [
("E06", "tree, depth 3", "Decision tree, max_depth=3", "Far below E03."),
("E07", "tree, depth 6", "Decision tree, max_depth=6", "The best of the three trees, still far below E03."),
("E08", "tree, no limit", "Decision tree, no depth limit",
"It memorises train (train AP 1.000) and fails on new tickets."),
]:
log_experiment(row_id, change, results[name]["CV AP"], results[name]["std"], None, "reject", reason)
show_log()
Sortie
id change cv_ap cv_std valid_ap decision
E01 Baseline: one score for every ticket (the train rate) 0.117 0.000 0.155 baseline
E02 Baseline: the rule 'flag priority 1', as a 0/1 score 0.178 0.008 0.228 baseline
E03 Logistic regression, the 10 C04 features 0.327 0.012 0.353 keep
E04 E03 with class_weight='balanced' 0.323 0.012 reject
E05 Baseline: the rule 'flag priority 1 or team payment' 0.172 0.006 reject
E06 Decision tree, max_depth=3 0.234 0.011 reject
E07 Decision tree, max_depth=6 0.258 0.010 reject
E08 Decision tree, no depth limit 0.137 0.004 reject

Aucun des arbres n’est un candidat, donc l’AP de validation reste vide. E03 reste le modèle à garder.

Changez une condition : construisez un arbre avec max_depth=4. Avant de l’exécuter, faites une prédiction : son AP de validation croisée sera-t-elle entre celles des arbres de profondeur 3 (0,234) et 6 (0,258)? Son AP d’entraînement sera-t-elle plus proche de son AP de validation croisée qu’à la profondeur 6?

print(evaluate(tree_pipeline(DecisionTreeClassifier(max_depth=4, random_state=0))))
Afficher la réponse
Sortie
{'train AP': 0.275, 'CV AP': 0.247, 'std': 0.008}

Oui aux deux questions. L’AP de validation croisée, 0,247, se situe entre celles des deux autres arbres. L’écart entre l’AP d’entraînement et de validation croisée est de 0,028, contre 0,010 à la profondeur 3 et 0,088 à la profondeur 6. Chaque niveau de questions supplémentaire s’ajuste plus étroitement aux billets d’entraînement, et l’écart grandit. La prochaine leçon suit cet écart pour chaque profondeur de 1 à 20.

Un arbre seul a de vraies forces :

  • Vous pouvez le lire. Un petit arbre est une liste de vérification qu’une personne peut suivre et vérifier, comme les questions de l’infirmière.
  • Il demande peu de préparation. Aucune mise à l’échelle, et il traite les nombres et les catégories de la même façon.
  • Il trouve des interactions. Il peut poser une question différente dans chaque branche.

Il a aussi de vraies faiblesses :

  • Il est instable. Un petit changement dans les billets d’entraînement peut changer la première question, puis tout l’arbre.
  • Ses scores manquent de finesse. Tous les billets d’une feuille reçoivent le même score.
  • Un arbre profond mémorise. Sans limite, il apprend le bruit, comme le montrent les scores de 1,000 et 0,137.

Un petit arbre seul est donc utile quand des personnes doivent suivre ou vérifier les règles. Comme modèle de prédiction utilisé seul, il est généralement plus faible que d’autres modèles. La prochaine leçon montre comment limiter la complexité d’un arbre. La suivante, Les méthodes d’ensemble, montre comment plusieurs arbres ensemble corrigent l’instabilité.

Erreur courante

Une règle tirée de deux billets

Symptôme : Tomás lit l’arbre de profondeur 6 et trouve une feuille dont le score est de 1,0. Il dit à Grace : « Les billets de priorité 3 dont la commande vaut entre 190,53 $ et 190,80 $ sont toujours transférés. » L’arbre contient bien cette feuille :

deep = tree_pipeline(DecisionTreeClassifier(max_depth=6, random_state=0)).fit(train[FEATURES], train[TARGET])
leaf_of_ticket = deep.named_steps["model"].apply(deep.named_steps["prepare"].transform(train[FEATURES]))
leaf_sizes = pd.Series(leaf_of_ticket).value_counts()
small = leaf_sizes[leaf_sizes < 10].index
pure = [leaf for leaf in small if train[TARGET][leaf_of_ticket == leaf].nunique() == 1]
print(len(leaf_sizes), "leaves;", len(small), "with fewer than 10 train tickets;", len(pure), "of these are pure")
print(train.loc[leaf_of_ticket == 113, ["ticket_id", "priority", "order_value", TARGET]].to_string(index=False))

apply() donne le numéro de la feuille où aboutit chaque billet. Le résultat :

Sortie
59 leaves; 18 with fewer than 10 train tickets; 13 of these are pure
ticket_id priority order_value escalated_72h
T-113665 3 190.56 1
T-116778 3 190.64 1

Cause : la « règle » vient de deux billets. Les seuils de 190,53 $ et de 190,80 $ séparent seulement ces deux billets de leurs voisins. L’arbre de profondeur 6 compte 59 feuilles, dont 18 contiennent moins de 10 billets d’entraînement. Parmi ces 18 feuilles, 13 sont pures, seulement par hasard. Une feuille de deux billets obtient très facilement un score de 0 ou de 1. De même, deux lancers d’une pièce donnent tous deux face une fois sur quatre.

Correction : ne lisez jamais le score d’une feuille sans connaître son nombre de billets. Limitez l’arbre pour que chaque feuille contienne assez de billets : min_samples_leaf, dans la prochaine leçon. Jugez l’arbre selon son AP en validation croisée, pas selon ses feuilles les plus frappantes.

Conséquence dans le travail en IA : les règles tirées de petites feuilles semblent précises et convaincantes. Une équipe qui les applique change un processus à cause de deux billets. Le même piège existe avec tout petit groupe de données : montrez toujours le nombre à côté du taux.

Vérifiez votre compréhension

Pour les 10 billets, une troisième question est « priorité = 3? ». Elle forme deux groupes : 3 billets sans transfert et 7 billets avec 4 transferts. Calculez l'impureté après cette séparation. L'arbre la choisirait-il plutôt que « priorité = 1? » (0,317)?

Afficher la réponse

Le groupe oui est pur : 2 × 0 × 1 = 0. Le groupe non a p = 4/7, donc 2 × 4/7 × 3/7 = 0,490. En pondérant selon la taille : (3 × 0 + 7 × 0,490) ÷ 10 = 0,343. C’est plus élevé que 0,317, donc l’arbre choisit encore « priorité = 1? ». Un groupe pur ne suffit pas à gagner : l’autre groupe doit aussi devenir plus pur.

Vérifiez votre compréhension

L'arbre sans limite obtient une AP d'entraînement de 1,000 et une AP en validation croisée de 0,137. La régression logistique obtient 0,328 et 0,327. Omar demande quel modèle a appris le plus. Que répondez-vous?

Afficher la réponse

L’arbre a appris davantage sur les billets d’entraînement : il s’ajuste exactement à chacun. Mais il a surtout appris du bruit qui ne se répète pas dans les nouveaux billets. Son AP en validation croisée est donc proche du plancher de 0,117. La régression logistique a appris moins de détails, mais ce qu’elle a appris fonctionne sur des billets jamais vus. Pour Larkfield, seul le score sur les nouveaux billets compte. La régression logistique est donc le meilleur modèle.

Vérifiez votre compréhension

Un collègue dit : « Un arbre peut trouver des interactions, contrairement à la régression logistique. Un arbre est donc toujours meilleur. » Utilisez les résultats de validation croisée pour répondre.

Afficher la réponse

La capacité à trouver des interactions aide seulement quand les données en contiennent de fortes. Ici, le meilleur arbre obtient une AP en validation croisée de 0,258, contre 0,327 pour la régression logistique. C’est une différence réelle de plus de cinq écarts-types. Chez Larkfield, le risque vient surtout de faits qui ajoutent chacun un certain risque à eux seuls. C’est la forme de la régression logistique. Aucune famille de modèles n’est toujours meilleure : les données décident, et vous le mesurez.

Récapitulatif

  • Un arbre de décision pose des questions oui ou non dans l’ordre. À chaque séparation, il choisit la question qui réduit le plus l’impureté de Gini. Le score d’une feuille est la proportion de ses billets d’entraînement transférés.
  • Un arbre peut utiliser une question différente dans chaque branche. Il peut donc trouver des interactions. Il n’a pas besoin de mise à l’échelle.
  • L’arbre réel de profondeur 2 sépare les billets selon la priorité 1, puis selon le nombre de mots. Sa feuille la plus risquée obtient un score de 0,348.
  • Sur les mêmes plis de validation, les arbres font moins bien que la régression logistique. L’arbre de profondeur 6 obtient 0,258, contre 0,327 ± 0,012 pour la régression logistique. Un arbre sans limite mémorise : AP d’entraînement de 1,000, AP en validation croisée de 0,137.
  • Votre journal compte huit lignes. Ne lisez jamais le score d’une feuille sans connaître son nombre de billets.

Ensuite, vous contrôlerez la complexité d’un modèle et verrez quand il apprend trop peu ou trop.

Leçon suivante : Contrôler la complexité