Análisis del árbol de decisión

Machine LearningMachine LearningBeginner
Practicar Ahora

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

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

El clasificador de árbol de decisión es un algoritmo de aprendizaje automático popular utilizado para problemas de clasificación y regresión. Es un modelo basado en árboles que divide el espacio de características en un conjunto de regiones no superpuestas y predice el valor objetivo para cada región. En este laboratorio, aprenderemos cómo analizar la estructura del árbol de decisión para obtener una comprensión más profunda de la relación entre las características y el objetivo a predecir.

Consejos sobre la VM

Una vez finalizada la inicialización de la VM, haga clic en la esquina superior izquierda para cambiar a la pestaña Cuaderno y acceder a Jupyter Notebook para practicar.

A veces, es posible que tenga que esperar unos segundos a que Jupyter Notebook termine de cargarse. La validación de las operaciones no se puede automatizar debido a las limitaciones de Jupyter Notebook.

Si tiene problemas durante el aprendizaje, no dude en preguntar a Labby. Deje su retroalimentación después de la sesión y resolveremos rápidamente el problema para usted.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL sklearn(("Sklearn")) -.-> sklearn/CoreModelsandAlgorithmsGroup(["Core Models and Algorithms"]) sklearn(("Sklearn")) -.-> sklearn/ModelSelectionandEvaluationGroup(["Model Selection and Evaluation"]) sklearn(("Sklearn")) -.-> sklearn/UtilitiesandDatasetsGroup(["Utilities and Datasets"]) ml(("Machine Learning")) -.-> ml/FrameworkandSoftwareGroup(["Framework and Software"]) 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{{"Análisis del árbol de decisión"}} sklearn/model_selection -.-> lab-49325{{"Análisis del árbol de decisión"}} sklearn/datasets -.-> lab-49325{{"Análisis del árbol de decisión"}} ml/sklearn -.-> lab-49325{{"Análisis del árbol de decisión"}} end

Entrenar un clasificador de árbol de decisión

En primer lugar, necesitamos ajustar un clasificador de árbol de decisión utilizando el conjunto de datos load_iris de scikit-learn. Este conjunto de datos contiene 3 clases de 50 instancias cada una, donde cada clase se refiere a un tipo de planta de iris. Dividiremos el conjunto de datos en conjuntos de entrenamiento y prueba y ajustaremos un clasificador de árbol de decisión con un máximo de 3 nodos hoja.

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)

Analizar la estructura del árbol binario

El clasificador de árbol de decisión tiene un atributo llamado tree_ que permite acceder a atributos de bajo nivel como node_count, el número total de nodos, y max_depth, la profundidad máxima del árbol. También almacena la estructura completa del árbol binario, representada como una serie de arrays paralelos. Utilizando estos arrays, podemos recorrer la estructura del árbol para calcular propiedades diversas, como la profundidad de cada nodo y si es o no una hoja. A continuación se muestra el código para calcular estas propiedades:

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)]  ## comienza con el id del nodo raíz (0) y su profundidad (0)
while len(stack) > 0:
    ## `pop` asegura que cada nodo solo sea visitado una vez
    node_id, depth = stack.pop()
    node_depth[node_id] = depth

    ## Si el hijo izquierdo y derecho de un nodo no son iguales, tenemos un nodo de división
    is_split_node = children_left[node_id]!= children_right[node_id]
    ## Si es un nodo de división, agrega los hijos izquierdo y derecho y la profundidad a `stack`
    ## para que podamos recorrerlos
    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 estructura del árbol binario tiene {n} nodos y tiene "
    "la siguiente estructura de árbol:\n".format(n=n_nodes)
)
for i in range(n_nodes):
    if is_leaves[i]:
        print(
            "{space}nodo={node} es un nodo hoja.".format(
                space=node_depth[i] * "\t", node=i
            )
        )
    else:
        print(
            "{space}nodo={node} es un nodo de división: "
            "ve al nodo {left} si X[:, {feature}] <= {threshold} "
            "sino al nodo {right}.".format(
                space=node_depth[i] * "\t",
                node=i,
                left=children_left[i],
                feature=feature[i],
                threshold=threshold[i],
                right=children_right[i],
            )
        )

Visualizar el árbol de decisión

También podemos visualizar el árbol de decisión utilizando la función plot_tree del módulo tree de scikit-learn.

from sklearn import tree
import matplotlib.pyplot as plt

tree.plot_tree(clf)
plt.show()

Obtener el camino de decisión y los nodos hoja

Podemos obtener el camino de decisión de las muestras de interés utilizando el método decision_path. Este método devuelve una matriz de indicadores que nos permite recuperar los nodos por los que atraviesan las muestras de interés. Los ids de las hojas alcanzadas por las muestras de interés se pueden obtener con el método apply. Esto devuelve una matriz con los ids de los nodos de las hojas alcanzadas por cada muestra de interés. Utilizando los ids de las hojas y el decision_path podemos obtener las condiciones de división que se utilizaron para predecir una muestra o un grupo de muestras. A continuación se muestra el código para obtener el camino de decisión y los nodos hoja para una muestra:

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

sample_id = 0
## obtener los ids de los nodos por los que pasa `sample_id`, es decir, la fila `sample_id`
node_index = node_indicator.indices[
    node_indicator.indptr[sample_id] : node_indicator.indptr[sample_id + 1]
]

print("Reglas utilizadas para predecir la muestra {id}:\n".format(id=sample_id))
for node_id in node_index:
    ## continuar con el siguiente nodo si es un nodo hoja
    if leaf_id[sample_id] == node_id:
        continue

    ## comprobar si el valor de la característica de división para la muestra 0 es menor que el umbral
    if X_test[sample_id, feature[node_id]] <= threshold[node_id]:
        threshold_sign = "<="
    else:
        threshold_sign = ">"

    print(
        "nodo de decisión {node} : (X_test[{sample}, {feature}] = {value}) "
        "{inequality} {threshold})".format(
            node=node_id,
            sample=sample_id,
            feature=feature[node_id],
            value=X_test[sample_id, feature[node_id]],
            inequality=threshold_sign,
            threshold=threshold[node_id],
        )
    )

Determinar los nodos comunes para un grupo de muestras

Para un grupo de muestras, podemos determinar los nodos comunes por los que pasan las muestras utilizando el método decision_path y el método toarray para convertir la matriz de indicadores en una matriz densa.

sample_ids = [0, 1]
## matriz booleana que indica los nodos por los que pasan ambas muestras
common_nodes = node_indicator.toarray()[sample_ids].sum(axis=0) == len(sample_ids)
## obtener los ids de los nodos utilizando su posición en la matriz
common_node_id = np.arange(n_nodes)[common_nodes]

print(
    "\nLas siguientes muestras {samples} comparten el nodo(s) {nodes} en el árbol.".format(
        samples=sample_ids, nodes=common_node_id
    )
)
print("Esto es el {prop}% de todos los nodos.".format(prop=100 * len(common_node_id) / n_nodes))

Resumen

En este laboratorio, hemos aprendido cómo analizar la estructura del árbol de decisión para obtener una comprensión más profunda de la relación entre las características y la variable objetivo a predecir. Hemos visto cómo recuperar la estructura del árbol binario, visualizar el árbol de decisión y recuperar el camino de decisión y los nodos hoja para una muestra o un grupo de muestras. Estas técnicas pueden ayudarnos a entender mejor cómo el clasificador de árbol de decisión realiza sus predicciones y pueden guiarnos en el ajuste fino del modelo para mejorar su rendimiento.