Analyse d'arbre de décision

Machine LearningMachine LearningBeginner
Pratiquer maintenant

This tutorial is from open-source community. Access the source code

💡 Ce tutoriel est traduit par l'IA à partir de la version anglaise. Pour voir la version originale, vous pouvez cliquer ici

Introduction

Le classifieur d'arbre de décision est un algorithme d'apprentissage automatique populaire utilisé pour les problèmes de classification et de régression. C'est un modèle basé sur un arbre qui divise l'espace de caractéristiques en un ensemble de régions non superposées et prédit la valeur cible pour chaque région. Dans ce laboratoire, nous allons apprendre à analyser la structure de l'arbre de décision pour mieux comprendre la relation entre les caractéristiques et la cible à prédire.

Conseils sur la machine virtuelle

Une fois le démarrage de la machine virtuelle terminé, cliquez dans le coin supérieur gauche pour basculer vers l'onglet Carnet de notes pour accéder à Jupyter Notebook pour la pratique.

Parfois, vous devrez peut-être attendre quelques secondes pour que Jupyter Notebook ait fini de charger. La validation des opérations ne peut pas être automatisée en raison des limitations de Jupyter Notebook.

Si vous rencontrez des problèmes pendant l'apprentissage, n'hésitez pas à demander à Labby. Donnez votre feedback après la session, et nous réglerons rapidement le problème pour vous.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL sklearn(("Sklearn")) -.-> sklearn/ModelSelectionandEvaluationGroup(["Model Selection and Evaluation"]) sklearn(("Sklearn")) -.-> sklearn/UtilitiesandDatasetsGroup(["Utilities and Datasets"]) ml(("Machine Learning")) -.-> ml/FrameworkandSoftwareGroup(["Framework and Software"]) sklearn(("Sklearn")) -.-> sklearn/CoreModelsandAlgorithmsGroup(["Core Models and Algorithms"]) sklearn/CoreModelsandAlgorithmsGroup -.-> sklearn/tree("Decision Trees") sklearn/ModelSelectionandEvaluationGroup -.-> sklearn/model_selection("Model Selection") sklearn/UtilitiesandDatasetsGroup -.-> sklearn/datasets("Datasets") ml/FrameworkandSoftwareGroup -.-> ml/sklearn("scikit-learn") subgraph Lab Skills sklearn/tree -.-> lab-49325{{"Analyse d'arbre de décision"}} sklearn/model_selection -.-> lab-49325{{"Analyse d'arbre de décision"}} sklearn/datasets -.-> lab-49325{{"Analyse d'arbre de décision"}} ml/sklearn -.-> lab-49325{{"Analyse d'arbre de décision"}} end

Entraîner un classifieur d'arbre de décision

Tout d'abord, nous devons ajuster un classifieur d'arbre de décision en utilisant le jeu de données load_iris de scikit-learn. Ce jeu de données contient 3 classes de 50 instances chacune, où chaque classe fait référence à un type de plante d'iris. Nous allons diviser le jeu de données en ensembles d'entraînement et de test et ajuster un classifieur d'arbre de décision avec un maximum de 3 nœuds terminaux.

from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier

iris = load_iris()
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

clf = DecisionTreeClassifier(max_leaf_nodes=3, random_state=0)
clf.fit(X_train, y_train)

Analyser la structure de l'arbre binaire

Le classifieur d'arbre de décision possède un attribut appelé tree_ qui permet d'accéder à des attributs de bas niveau tels que node_count, le nombre total de nœuds, et max_depth, la profondeur maximale de l'arbre. Il stocke également toute la structure de l'arbre binaire, représentée sous forme de plusieurs tableaux parallèles. En utilisant ces tableaux, nous pouvons parcourir la structure de l'arbre pour calculer diverses propriétés telles que la profondeur de chaque nœud et s'il s'agit ou non d'un nœud terminal. Voici le code pour calculer ces propriétés :

import numpy as np

n_nodes = clf.tree_.node_count
children_left = clf.tree_.children_left
children_right = clf.tree_.children_right
feature = clf.tree_.feature
threshold = clf.tree_.threshold

node_depth = np.zeros(shape=n_nodes, dtype=np.int64)
is_leaves = np.zeros(shape=n_nodes, dtype=bool)
stack = [(0, 0)]  ## commencer par l'identifiant du nœud racine (0) et sa profondeur (0)
while len(stack) > 0:
    ## `pop` assure que chaque nœud est visité une seule fois
    node_id, depth = stack.pop()
    node_depth[node_id] = depth

    ## Si l'enfant gauche et droit d'un nœud sont différents, nous avons un nœud de division
    is_split_node = children_left[node_id]!= children_right[node_id]
    ## Si un nœud de division, ajoutez les enfants gauche et droit et la profondeur à `stack`
    ## afin que nous puissions parcourir à travers eux
    if is_split_node:
        stack.append((children_left[node_id], depth + 1))
        stack.append((children_right[node_id], depth + 1))
    else:
        is_leaves[node_id] = True

print(
    "La structure de l'arbre binaire a {n} nœuds et a "
    "la structure d'arbre suivante :\n".format(n=n_nodes)
)
for i in range(n_nodes):
    if is_leaves[i]:
        print(
            "{espace}nœud={node} est un nœud terminal.".format(
                espace=node_depth[i] * "\t", node=i
            )
        )
    else:
        print(
            "{espace}nœud={node} est un nœud de division : "
            "aller au nœud {gauche} si X[:, {caractéristique}] <= {seuil} "
            "sinon au nœud {droite}.".format(
                espace=node_depth[i] * "\t",
                node=i,
                gauche=children_left[i],
                caractéristique=feature[i],
                seuil=threshold[i],
                droite=children_right[i],
            )
        )

Visualiser l'arbre de décision

Nous pouvons également visualiser l'arbre de décision à l'aide de la fonction plot_tree du module tree de scikit-learn.

from sklearn import tree
import matplotlib.pyplot as plt

tree.plot_tree(clf)
plt.show()

Récupérer le chemin de décision et les nœuds terminaux

Nous pouvons récupérer le chemin de décision d'échantillons d'intérêt à l'aide de la méthode decision_path. Cette méthode renvoie une matrice d'indicateurs qui nous permet de récupérer les nœuds traversés par les échantillons d'intérêt. Les identifiants des nœuds terminaux atteints par les échantillons d'intérêt peuvent être obtenus avec la méthode apply. Cela renvoie un tableau des identifiants des nœuds des nœuds terminaux atteints par chaque échantillon d'intérêt. En utilisant les identifiants des nœuds terminaux et le decision_path, nous pouvons obtenir les conditions de division qui ont été utilisées pour prédire un échantillon ou un groupe d'échantillons. Voici le code pour récupérer le chemin de décision et les nœuds terminaux pour un échantillon :

node_indicator = clf.decision_path(X_test)
leaf_id = clf.apply(X_test)

sample_id = 0
## obtenir les identifiants des nœuds que `sample_id` traverse, c'est-à-dire la ligne `sample_id`
node_index = node_indicator.indices[
    node_indicator.indptr[sample_id] : node_indicator.indptr[sample_id + 1]
]

print("Règles utilisées pour prédire l'échantillon {id}:\n".format(id=sample_id))
for node_id in node_index:
    ## passer au nœud suivant s'il s'agit d'un nœud terminal
    if leaf_id[sample_id] == node_id:
        continue

    ## vérifier si la valeur de la caractéristique de division pour l'échantillon 0 est inférieure au seuil
    if X_test[sample_id, feature[node_id]] <= threshold[node_id]:
        threshold_sign = "<="
    else:
        threshold_sign = ">"

    print(
        "nœud de décision {node} : (X_test[{sample}, {caractéristique}] = {valeur}) "
        "{inégalité} {seuil})".format(
            node=node_id,
            sample=sample_id,
            caractéristique=feature[node_id],
            valeur=X_test[sample_id, feature[node_id]],
            inégalité=threshold_sign,
            seuil=threshold[node_id],
        )
    )

Déterminer les nœuds communs pour un groupe d'échantillons

Pour un groupe d'échantillons, nous pouvons déterminer les nœuds communs que les échantillons traversent en utilisant la méthode decision_path et la méthode toarray pour convertir la matrice d'indicateurs en un tableau dense.

sample_ids = [0, 1]
## tableau booléen indiquant les nœuds traversés par les deux échantillons
common_nodes = node_indicator.toarray()[sample_ids].sum(axis=0) == len(sample_ids)
## obtenir les identifiants de nœuds en utilisant leur position dans le tableau
common_node_id = np.arange(n_nodes)[common_nodes]

print(
    "\nLes échantillons suivants {samples} partagent le ou les nœuds {nodes} dans l'arbre.".format(
        samples=sample_ids, nodes=common_node_id
    )
)
print("Ceci représente {prop}% de tous les nœuds.".format(prop=100 * len(common_node_id) / n_nodes))

Récapitulatif

Dans ce laboratoire, nous avons appris à analyser la structure de l'arbre de décision pour mieux comprendre la relation entre les caractéristiques et la variable cible à prédire. Nous avons vu comment récupérer la structure de l'arbre binaire, visualiser l'arbre de décision et récupérer le chemin de décision et les nœuds terminaux pour un échantillon ou un groupe d'échantillons. Ces techniques peuvent nous aider à mieux comprendre comment le classifieur d'arbre de décision effectue ses prédictions et peuvent nous guider dans l'ajustement fin du modèle pour améliorer ses performances.