Está en la página 1de 13

8/5/22, 00:17 Capítulo 6 - Árboles de decisión.

ipynb - Colaboratory

Al igual que los SVM, los árboles de decisión son algoritmos de Machine Learning que pueden
realizar clasificación y regresión, incluso tareas multisalida. Son algoritmos muy poderosos,
capaces de ajusta datasets complejos.

Son también los componenetes fundamentales de Random Forest, los cuales son los
algorimtos más poderosos disponibles en la actualidad.

En este capítulo discutiremos cómo entrenar, visualizar y hacer predicciones con Arboles de
Decisión. Luego veremos cómo regular árboles y usarlos para tareas de regresión. Finalmente,
discutiremos algunas de las limitaciones de los Arboles de Decisión.

Entrenando y visualizando árboles de decisión


Para comprender los árboles de decisión, vamos a construir uno y dar un vistazo de cómo este
hace predicciones. El siguiente código entran un DecisiionTreeClassifier en el dataset iris:

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

import numpy as np
np.random.seed(42)

iris = load_iris()
X = iris.data[:, 2:] # largo y ancho de pétalos
y = iris.target
tree_clf = DecisionTreeClassifier(max_depth=2)
tree_clf.fit(X, y)

DecisionTreeClassifier(max_depth=2)

Puedes visualizar el árbol de decisión entrenado usando el método export_graphviz() para


mostrar un archivo de definición gráfico llamado iris_tree.dot:

from sklearn.tree import export_graphviz
export_graphviz(
        tree_clf,
        out_file="iris_tree.dot",
        feature_names=iris.feature_names[2:],
        class_names=iris.target_names,
        rounded=True,
        filled=True
    )

from subprocess import call
call(['dot', '-Tpng', 'iris_tree.dot', '-o', 'iris_tree.png', '-Gdpi=100'])

from IPython.display import Image
( )
https://colab.research.google.com/drive/1AJiEjm5Fq1V2-Zl1_tUSLapyvpVPZQlB?usp=sharing#printMode=true 1/13
8/5/22, 00:17 Capítulo 6 - Árboles de decisión.ipynb - Colaboratory
Image(filename = 'iris_tree.png')

Haciendo predicciones
Suponiendo que encuentras una flor Iris y quieres clasificarla. Empezarías en el nodo raiz: este
nodo pregunta si la longitud del pétalo de la flor es mas pequeña que 2.45 cm. Si es así,
entonces te mueves hacia abjo al nodo hijo izquierdo (profundidad 1, left). En este caso, si este
es un nodo hoja (que no tiene nodos hijos), por lo que no hace ninguna pregunat: puedes
simplemente ver en la clase predicha para este nodo y el Arbol de Decisión predice que tu flor es
Iris-Setosa (class=setosa).

Ahora supón que encuentras otra flor, pero esta vez la longitud del pétalo es mas grande que
2.45 cm. Deberías moverte hacia abajo al nodo hijo derecho (profundidad 1, derecha), el cual no
es un nodo hoja, de modo que éste hace otra pregunta: ¿Es el pétalo de un ancho menor que
1.75? Si es así, entonces tu flor es más parecida a una Iris-Versicolor (profundidad 2, izquierda).
Si no, es parecida a Iris-Virginica (profundidad 2, derecha). Esto es realmente simple.

Un atributo del nodo samples cuenta la cantidad de instancias de entrenamiento aplicadas. Por
ejemplo, 100 instancias de entrenamiento tienen una longitud de pétalo mayor que 2.45 cm
(profundidad 1, derecha), de los cuaels 54 tienen un ancho de pétalo mas pequeño que 1.75 cm
(profundidad 2, izquierda). Un atributo del nodo value te dice cúantas instancia de
entrenamiento de cada clase se aplican a este nodo: por ejemplo, el nodo abajo a la dereha se
aplica a 0 Iris-setosa, 1 Iris-versicolor y 45 Iris-virginica. Finalmente, un atributo gini mide su
impureza: un nodo es puro (gini=0) si todas las instancia de entrenamiento llegan a ser de la

https://colab.research.google.com/drive/1AJiEjm5Fq1V2-Zl1_tUSLapyvpVPZQlB?usp=sharing#printMode=true 2/13
8/5/22, 00:17 Capítulo 6 - Árboles de decisión.ipynb - Colaboratory

misma clase. Por ejemplo, dado que el nodo izquierdo de profundidad-1 aplica sólo a instancias
de entrenamiento de Iris-Setosa, es puro y si puntaje gini es 0,

# Este codigo solo genera el grafico siguiente

from matplotlib.colors import ListedColormap

import matplotlib.pyplot as plt

import numpy as np

def plot_decision_boundary(clf, X, y, axes=[0, 7.5, 0, 3], iris=True, legend=False, plot_t
    x1s = np.linspace(axes[0], axes[1], 100)

    x2s = np.linspace(axes[2], axes[3], 100)

    x1, x2 = np.meshgrid(x1s, x2s)

    X_new = np.c_[x1.ravel(), x2.ravel()]

    y_pred = clf.predict(X_new).reshape(x1.shape)

    custom_cmap = ListedColormap(['#fafab0','#9898ff','#a0faa0'])

    plt.contourf(x1, x2, y_pred, alpha=0.3, cmap=custom_cmap)

    if not iris:

        custom_cmap2 = ListedColormap(['#7d7d58','#4c4c7f','#507d50'])

        plt.contour(x1, x2, y_pred, cmap=custom_cmap2, alpha=0.8)

    if plot_training:

        plt.plot(X[:, 0][y==0], X[:, 1][y==0], "yo", label="Iris setosa")

        plt.plot(X[:, 0][y==1], X[:, 1][y==1], "bs", label="Iris versicolor")

        plt.plot(X[:, 0][y==2], X[:, 1][y==2], "g^", label="Iris virginica")

        plt.axis(axes)

    if iris:

        plt.xlabel("Petal length", fontsize=14)

        plt.ylabel("Petal width", fontsize=14)

    else:

        plt.xlabel(r"$x_1$", fontsize=18)

        plt.ylabel(r"$x_2$", fontsize=18, rotation=0)

    if legend:

        plt.legend(loc="lower right", fontsize=14)

plt.figure(figsize=(8, 4))

plot_decision_boundary(tree_clf, X, y)

plt.plot([2.45, 2.45], [0, 3], "k-", linewidth=2)
plt.plot([2.45, 7.5], [1.75, 1.75], "k--", linewidth=2)

plt.plot([4.95, 4.95], [0, 1.75], "k:", linewidth=2)

plt.plot([4.85, 4.85], [1.75, 3], "k:", linewidth=2)

plt.text(1.40, 1.0, "Depth=0", fontsize=15)

plt.text(3.2, 1.80, "Depth=1", fontsize=13)

plt.text(4.05, 0.5, "(Depth=2)", fontsize=11)

plt.show()

https://colab.research.google.com/drive/1AJiEjm5Fq1V2-Zl1_tUSLapyvpVPZQlB?usp=sharing#printMode=true 3/13
8/5/22, 00:17 Capítulo 6 - Árboles de decisión.ipynb - Colaboratory

La figura muestar el vecindario de decisión. La linea vertical delgada representa el vecindario de


decisión del nodo raiz (profundidad 0): la longitud del pétalo = 2.45 cm. Dado que el area es pura
(sólo Iris-Setosa), este no puede ser dividido más. Sin embargo, el area derecha es impura, de
forma que el nodo a la derecha a profundidad 1 lo divide en un ancho de pétalo = 1.75 cm (
representado por la linea punteada). Dado que max_depth se establece a 2, el Árbol de Decisión
se detiene aquí. Sin embargo, si estableces max_depth a 3, entonces los nodos de profundidad
2 podrían cada uno agregar otro vecindario de decisión (representado por las lineas punteadas).

Estimando probabilidades de las clases


Un árbol de decisión puede también estimar la probabilidad que una instancia pertenece a una
clase particular k ; primero este recorre el árbol para encontrar un nodo hoja para esta instancia,
y entonces devuelve el ratio de instancias de entrenamiento de la clase k en este nodo. Por
ejemplo, suponiendo que has encontrado una flor cuyos pétalos son de 5 cm de largo y 1.5 cm
de ancho. El correspondiente nodo hoja es el nodo a la izquierda de profundidad-2, por lo que el
árbol de decisión debe sacar las siguientes probabilidades: 0% para Iris-Setosa (0/54), 90.7%
para Iris-Versicolor (49/54), y 9,3% para Iris-Virginica (5/54). Y por supuesto si preguntas esto
para predecir la clase, este debe mostrar Iris-Versicolor(clase I) dado que tiene la probabilidad
más alta. Vamos a verificar esto:

tree_clf.predict_proba([[3.5, 3.3]])

array([[0. , 0.02173913, 0.97826087]])

tree_clf.predict([[3.5, 3.3]])

array([2])

Perfecto. Nota que las probabilidades serán identicas para cualquier en el rectángulo abajo a la
derecha, si los pétalos fueran 6cm de largo y 1.5cm de ancho (aún que parezca obvio que
debería ser un Iris-virginica en este caso).

El algoritmo de entrenamiento CART

https://colab.research.google.com/drive/1AJiEjm5Fq1V2-Zl1_tUSLapyvpVPZQlB?usp=sharing#printMode=true 4/13
8/5/22, 00:17 Capítulo 6 - Árboles de decisión.ipynb - Colaboratory

Scikit-Learn utiliza el algoritmo Árbol de clasificación y regresión (CART) para entrenar árboles
de decisión (también llamado "creciendo" árboles). La idea es realmente simple: el algoritmo
primero divide el conjunto de entrenamiento en dos subcojuntos usando una característica k y
un umbral tk (longitud de pétalo menor o igual a 2.45 cm). ¿Cómo elegimos k y tK ? Si buscas
el par (k , tk ) que produce el subconjunto más puro (ponderado por su tamaño). La función de
costo que el algoritmo aplica para minimizar está dado por la ecuación:
mlef t mright
J (k, tk ) = Glef t + Gright
m m

Donde:

Glef t/right mide la impureza del subconjunto left/right


mlef t/right el la cantidad de instancia en el subconjunto left/right

Una vez que se ha divido el conjunto de entrenamiento en dos satisfactoriamente, este divide el
subconjunto usando la misma lógica, luego los sub-subconjuntos y así sucesivamente, de forma
recursiva. Se detiene la recursión una vez que se alcanza la profundidad máxima (definido por el
hiperparámetro max_depth ), o si no puede encontrar una división que pueda reducir la impureza.
Unos pocos hiperparámetros controlan condiciones adicionales de terminación
( min_samples_split, min_samples_leaf, min_weight_fraction_leaf, max_leaf_nodes ).

Como puedes ver el algoritmo CART es un algoritmo greedy: esta búsqueda una división óptima
en el nivel más alto, luego repite el proceso en cada nivel. Si no se verifica si la división permite
la impureza más baja varios niveles abajo. Un algoritmo greedy a menudo produce un solución
razonablemente buena, pero esto no garantiza que sea la solución óptima.

Desafortunadamente, encontrar el árbol óptimo es conocido por ser un problema NP-completo:


requiere O(exp(m)) de tiempo, haciendo que el problema sea intratable aún con conjuntos de
prueba bastante pequeños. Esto es porque debemos establecer una solución razonablemente
buena.

Complejidad computacional
Hacer predicciones requiere recorrer el árbol de decisión desde la raiz a las hojas. Los árboles
de decisión son generalmente balanceados aproximadamente, de modo que recorrer el Arbol de
Decisión requiere recorrer aproximadamente O(log2 (m)) nodos. Dado que cada nodo
solamente requiere verificar el valor de una característica, la complejidad de la predicción total
es justamente O(log2 (m)), independientemente de la cantidad de características. De modo
que las predicciones son bastante rápidas, aun cuando se hagan con grandes conjuntos de
entrenamiento.

Sin embargo, el algoritmo de entrenamiento compara todas las características (o menos si


max_features se ha establecido) sobre todas las muestras en cada nodo. Esto resulta en una
complejidad de entrenamiento de O(n × m × log(m)). Para conjutnos de entrenamiento
(menos de unos pocos cientos de instancias), Scikit-Learn puede apurar el entrenamiento

https://colab.research.google.com/drive/1AJiEjm5Fq1V2-Zl1_tUSLapyvpVPZQlB?usp=sharing#printMode=true 5/13
8/5/22, 00:17 Capítulo 6 - Árboles de decisión.ipynb - Colaboratory

cuando se reordena los datos (establecer presort=True ), pero esto relentiza el entrenamiento
considerablemente para conjuntos de datos más grandes.
¿Impureza Gini o Entropia?
Por defecto, se usó la medida de la impureza Gini, que es una medida de cuán a menudo un
elemento elegido aleatoriamente del conjunto sería etiquetado incorrectamente si fue
etiquetado de manera aleatoria de acuerdo a la distribución de las etiquetas en el subconjunto.
La impureza de Gini se puede calcular sumando la probabilidad de cada elemento siendo
elegido multiplicado por la probabilidad de un error en la categorización de ese elemento.
Alcanza su mínimo (cero) cuando todos los casos del nodo corresponden a una sola categoría
de destino. Pero puedes seleccionar la medida de impureza de entropía estableciendo el
hiperparámetro criterion a entropy . El concepto de entropía se originó en la termodinámica
como una medida del desorden molecular: la entropía se aproxima a cero cuando las molécular
están bien ordenadas. Esto luego pasó a una variedad de dominios, incluyendo la teoría de la
información de shanon, donde se mide el promedio de información contenida en un mensaje: La
entropía es cero cuando todos los mensajes son idénticos. En Machine Learning, se usa
frecuentemente usado como una medida de impureza: la entropía del conjunto es cero cuando
este contiene instancias de sólo una clase. La ecuación muestra la definición de entropía del
nodo ith . Por ejemplo, el nodo en la profundidad-2 tiene una entropía igual a
49 49 5 5
− log2 ( ) − log2 ( ) = 0.445
54 54 54 54

Hi = − ∑ pi,k log2 (pi,k )

k=1

¿Deberías usar la impureza Gini o la entropía? La verdad es, la mayoría de las veces no hay
mucha diferencia: ellos producen árboles similares. La impureza Gini es ligeramente más rápida
para calcular, por eso se usa por defecto. Sin embargo, cuando ellas difieren, la impureza Gini
tiende a aislar la clase más frecuente en su propia rama del árbol, mientras la entropía tiende a
producir árboles ligeramente más balanceados.

Regularización de hiperparámetros
Los árboles de decision hacen muy pocas suposiciones sobre la data de entrenamiento (en
oposición a modelos lineales, lo cual obviamente asume que la data es lineal, por ejemplo). Si
resulta sin restricciones, la estructura se adaptará a si misma a los datos de entrenamiento,
ajustándose muy cercanamente, y muy probablemente sobreentrenando. Tal modelo se llama a
menudo modelo no paramétrico, no por que este no tiene ningún parámetro (a menudo tiene
muchos) sino por que la cantidad de parámetros no está determinado antes del entrenamiento,
de forma que la estructura del modelo tiene una cantidad predeterminada de parámetros, de
modo que su grado de libertad está limitado, reduciendo el riesgo de sobreentrenamiento
(incrementando el riesto de subentrenamiento)

https://colab.research.google.com/drive/1AJiEjm5Fq1V2-Zl1_tUSLapyvpVPZQlB?usp=sharing#printMode=true 6/13
8/5/22, 00:17 Capítulo 6 - Árboles de decisión.ipynb - Colaboratory

Para evitar sobreentrenar la data de entrenamiento, necesitas restringir la libertad del árbol de
decisión durante el entrenamiento. Como sabes esto se llama regularización. El hiperparámetro
regularización depende del algoritmo usado, pero generalmente puedes restringir la máxima
profundidad del árbol de decisión. En Scikit-Learn, esto es controlado por el hiperparámetro
max_depth (el valor por defecto es None lo cual significa que es ilimitado). Reducir max_depth
puede regularizar el modelo y esto reduce el riesgo de sobreentrenamiento.

La clase DecisionTreeClassifier tiene algunos otros parámetros que de forma similar


restringen la forma del árbol de decisión: min_samples_split (la cantidad mínima de ejemplos
que puede tener un nodo antes que se haga la separación), min_samples_leaf (la cantidad
mínima de ejemplos que un nodo debe tener), min_weight_fraction_leaf (igual que
min_samples_leaf pero expresado como una fracción de la cantidad total de instancias
ponderadas), max_leaf_nodes (máximo número de nodos hoja), y max_features (máximo
número de características que son evaluadas para la separación en cada nodo). Incrementando
los hiperparámetros min_* o reduciendo max_* se regulariza el modelo.

La figura siguiente muestra dos árboles de decisión en el dataset "moons". A la izquierda, el


árbol de decisión se entrenó con los hiperparámetro (sin restricciones), y a la derecha el árbol
de decisión es entrenado con min_samples_leaf=4 . Esto es bastante obvio que el modelo de la
izquierda está sobreentrenado, y el modelo en la derecha será probablemente mejor
generalizado.

from sklearn.datasets import make_moons

Xm, ym = make_moons(n_samples=100, noise=0.25, random_state=53)

deep_tree_clf1 = DecisionTreeClassifier(random_state=42)

deep_tree_clf2 = DecisionTreeClassifier(max_depth=6, random_state=42)

deep_tree_clf1.fit(Xm, ym)

deep_tree_clf2.fit(Xm, ym)

fig, axes = plt.subplots(ncols=2, figsize=(10, 4), sharey=True)

plt.sca(axes[0])

plot_decision_boundary(deep_tree_clf1, Xm, ym, axes=[-1.5, 2.4, -1, 1.5], iris=False)

plt.title("No restrictions", fontsize=16)

plt.sca(axes[1])

plot_decision_boundary(deep_tree_clf2, Xm, ym, axes=[-1.5, 2.4, -1, 1.5], iris=False)

plt.title("min_samples_leaf = {}".format(deep_tree_clf2.min_samples_leaf), fontsize=14)

plt.ylabel("")

plt.show()

https://colab.research.google.com/drive/1AJiEjm5Fq1V2-Zl1_tUSLapyvpVPZQlB?usp=sharing#printMode=true 7/13
8/5/22, 00:17 Capítulo 6 - Árboles de decisión.ipynb - Colaboratory

Regresión
Los árboles de decisión también son capaes de tareas de regresión. Vamos a construir un árbol
de regresión usando la clase DecisionTreeRegressor de Scikit-Learn, entrenándolo en un
dataset con ruido cuadrático con max_depth=2 :

# conjunto cuadrático + ruido

np.random.seed(42)

m = 200

X = np.random.rand(m, 1)

y = 4 * (X - 0.5) ** 2

y = y + np.random.randn(m, 1) / 10

from sklearn.tree import DecisionTreeRegressor

tree_reg = DecisionTreeRegressor(max_depth=2)

tree_reg.fit(X, y)

DecisionTreeRegressor(max_depth=2)

export_graphviz(

        tree_reg,

        out_file="regression_tree.dot",

        feature_names=["x1"],

        rounded=True,

        filled=True

    )

from subprocess import call

call(['dot', '-Tpng', 'regression_tree.dot', '-o', 'regression_tree.png', '-Gdpi=100'])

from IPython.display import Image

Image(filename = 'regression_tree.png')

https://colab.research.google.com/drive/1AJiEjm5Fq1V2-Zl1_tUSLapyvpVPZQlB?usp=sharing#printMode=true 8/13
8/5/22, 00:17 Capítulo 6 - Árboles de decisión.ipynb - Colaboratory

Esto luce muy similar para el árbol de clasificación que construimos antes. La principal
diferencia es que en lugar de predecir una clase en cada nodo, esto predice un valor. Por
ejemplo, supon que quieres hacer una predicción para una nueva instancia con x1 = 0.6 .
Recorres del árbol empezando en la raiz, y eventualmente alcanzarás el nodo hoja que predice
value=0.1106 . Esta predicción es simplemente el valor promedio objetivo de las 110 instancias
de entrenamiento asociadas al nodo hoja. Esta predicción resulta en un Error Medio Cuadrático
(MSE) igual a 0.0151 sobre estas 110 instancias.

Estas predicciones del modelo son representadas a la izquierda en la figura siguiente. Si


estableces max_depth=3 , obtienes las predicciones representadas a la derecha. Note que el
valor predicho para cada región es siempre el valor promedio objetivo de las instancias en esta
región. El algoritmo divide cada región de forma que las instancias de entrenamiento estén lo
mas cerca posible del valor predicho.

from sklearn.tree import DecisionTreeRegressor

tree_reg1 = DecisionTreeRegressor(random_state=42, max_depth=2)

tree_reg2 = DecisionTreeRegressor(random_state=42, max_depth=3)

tree_reg1.fit(X, y)

tree_reg2.fit(X, y)

def plot_regression_predictions(tree_reg, X, y, axes=[0, 1, -0.2, 1], ylabel="$y$"):

    x1 = np.linspace(axes[0], axes[1], 500).reshape(-1, 1)

    y_pred = tree_reg.predict(x1)

    plt.axis(axes)

    plt.xlabel("$x_1$", fontsize=18)

    if ylabel:

        plt.ylabel(ylabel, fontsize=18, rotation=0)

    plt.plot(X, y, "b.")

    plt.plot(x1, y_pred, "r.-", linewidth=2, label=r"$\hat{y}$")

fig, axes = plt.subplots(ncols=2, figsize=(10, 4), sharey=True)

plt.sca(axes[0])

plot_regression_predictions(tree_reg1, X, y)

for split, style in ((0.1973, "k-"), (0.0917, "k--"), (0.7718, "k--")):

    plt.plot([split, split], [-0.2, 1], style, linewidth=2)

plt.text(0.21, 0.65, "Depth=0", fontsize=15)

plt.text(0.01, 0.2, "Depth=1", fontsize=13)

plt.text(0.65, 0.8, "Depth=1", fontsize=13)

plt.legend(loc="upper center", fontsize=18)

plt.title("max_depth=2", fontsize=14)

https://colab.research.google.com/drive/1AJiEjm5Fq1V2-Zl1_tUSLapyvpVPZQlB?usp=sharing#printMode=true 9/13
8/5/22, 00:17 Capítulo 6 - Árboles de decisión.ipynb - Colaboratory

plt.sca(axes[1])

plot_regression_predictions(tree_reg2, X, y, ylabel=None)

for split, style in ((0.1973, "k-"), (0.0917, "k--"), (0.7718, "k--")):

    plt.plot([split, split], [-0.2, 1], style, linewidth=2)

for split in (0.0458, 0.1298, 0.2873, 0.9040):

    plt.plot([split, split], [-0.2, 1], "k:", linewidth=1)

plt.text(0.3, 0.5, "Depth=2", fontsize=13)

plt.title("max_depth=3", fontsize=14)

plt.show()

El algoritmo CART trabaja principalmente de la misma forma, excepto que en lugar de tratar de
dividir el conjunto de entrenamiento en una forma que la impureza se minimiza, si ahora
intentamos dividir el conjunto de entrenamiento en una forma que minimiza el MSE. La ecuación
muestra que la función de costo que el algoritmo trata de minimizar:
mlef t mright
J (k, tk ) = M S Elef t + M S Eright
m m

Donde:
(i) 2
M S Enode = ^
∑ (y − y )
node

i∈node

1 (i)
y node = ∑ y
mnode

i∈node

Como en las tareas de clasificación. Los árboles de decisión son propensas a sobreentrenar
cuando tratamos con tareas de regresión. Sin ninguna regularización (usando los
hiperparámetros por defecto), obtienes las predicciones en la figura de la izquierda pero
obviamente está sobreentrenado. Al establecer min_samples_leaf=10 resulta en un modelo
mucho mas razonable, representado al a derecha.

tree_reg1 = DecisionTreeRegressor(random_state=42)

tree_reg2 = DecisionTreeRegressor(random_state=42, min_samples_leaf=10)

tree_reg1.fit(X, y)

https://colab.research.google.com/drive/1AJiEjm5Fq1V2-Zl1_tUSLapyvpVPZQlB?usp=sharing#printMode=true 10/13
8/5/22, 00:17 Capítulo 6 - Árboles de decisión.ipynb - Colaboratory

tree_reg2.fit(X, y)

x1 = np.linspace(0, 1, 500).reshape(-1, 1)

y_pred1 = tree_reg1.predict(x1)

y_pred2 = tree_reg2.predict(x1)

fig, axes = plt.subplots(ncols=2, figsize=(10, 4), sharey=True)

plt.sca(axes[0])

plt.plot(X, y, "b.")

plt.plot(x1, y_pred1, "r.-", linewidth=2, label=r"$\hat{y}$")

plt.axis([0, 1, -0.2, 1.1])

plt.xlabel("$x_1$", fontsize=18)

plt.ylabel("$y$", fontsize=18, rotation=0)

plt.legend(loc="upper center", fontsize=18)

plt.title("No restrictions", fontsize=14)

plt.sca(axes[1])

plt.plot(X, y, "b.")

plt.plot(x1, y_pred2, "r.-", linewidth=2, label=r"$\hat{y}$")

plt.axis([0, 1, -0.2, 1.1])

plt.xlabel("$x_1$", fontsize=18)

plt.title("min_samples_leaf={}".format(tree_reg2.min_samples_leaf), fontsize=14)

plt.show()

Inestabilidad
Ojalá por ahora estas convencido de que los árboles de decisión tienen mucho de bueno: son
simples de entender e interpretar, fáciles de usar, versatilidad, y poder. Sin embargo tienen
algunas limitaciones. Primero, como habrás notado, los árboles de decisión tienen vecindarios
de decisión ortogonales (todas las fivisiones son perpendiculares a los ejes), lo cual los hace
sensibles a las rotaciones del conjunto de entrenamiento. Por ejemplo la figura siguiente
muestra un dataset simple linealmente separable: a la izquierda, un árbol de decisión puede
dividirlo fácilmente, mientra que a la derecha, después de que el dataseta se roto 45º, el
https://colab.research.google.com/drive/1AJiEjm5Fq1V2-Zl1_tUSLapyvpVPZQlB?usp=sharing#printMode=true 11/13
8/5/22, 00:17 Capítulo 6 - Árboles de decisión.ipynb - Colaboratory

vecindario de decisión luce innecesariamente complejo. Sin embargo ambos árboles de


decisión aproximan el conjunto perfectamente, es muy probable que el modelo de la derecha no
generalice bien.

np.random.seed(6)

Xs = np.random.rand(100, 2) - 0.5

ys = (Xs[:, 0] > 0).astype(np.float32) * 2

angle = np.pi / 4

rotation_matrix = np.array([[np.cos(angle), -np.sin(angle)], [np.sin(angle), np.cos(angle)
Xsr = Xs.dot(rotation_matrix)

tree_clf_s = DecisionTreeClassifier(random_state=42)

tree_clf_s.fit(Xs, ys)

tree_clf_sr = DecisionTreeClassifier(random_state=42)

tree_clf_sr.fit(Xsr, ys)

fig, axes = plt.subplots(ncols=2, figsize=(10, 4), sharey=True)

plt.sca(axes[0])

plot_decision_boundary(tree_clf_s, Xs, ys, axes=[-0.7, 0.7, -0.7, 0.7], iris=False)

plt.sca(axes[1])

plot_decision_boundary(tree_clf_sr, Xsr, ys, axes=[-0.7, 0.7, -0.7, 0.7], iris=False)

plt.ylabel("")

plt.show()

Más generalmente, el principal tema con los árboles de decisión es que son muy sensitivo para
pequeñas variaciones de los datos de entrenamiento. Por ejemplo, si remueves completamente
Iris-Versicolor del conjunto de entrenamiento de iris y entrenas un nuevo árbol de decisión,
obtendrías el modelo representado en la siguiente figura. Esto luce muy diferentes del árbol de
decisión previo. Actualmente, dado que el algoritmo de entrenamiento usado por Scikit-Learn es
estocástico obtendrías diferentes modelos aún en los mismos datos de entrenamiento (a
menos que establezcas el hiperparámetro random_state ).

https://colab.research.google.com/drive/1AJiEjm5Fq1V2-Zl1_tUSLapyvpVPZQlB?usp=sharing#printMode=true 12/13
8/5/22, 00:17 Capítulo 6 - Árboles de decisión.ipynb - Colaboratory

https://colab.research.google.com/drive/1AJiEjm5Fq1V2-Zl1_tUSLapyvpVPZQlB?usp=sharing#printMode=true 13/13

También podría gustarte