HuatuCodeHuatuCode
Volver a Aprende
Machine Learning
HUATUCODE LECCIÓN/Machine Learning/DIFICULTAD: PRINCIPIANTE

Árboles de Decisión: De Preguntas Simples a Divisiones Matemáticas

Aprende cómo un algoritmo divide el espacio de datos en ramas lógicas usando la impureza de Gini y la ganancia de información (Information Gain) para clasificar y predecir.

#Árboles#Gini#Entropía#Information Gain#Partición
Árboles de Decisión: De Preguntas Simples a Divisiones Matemáticas
Laboratorio Práctico en Vivo

¿Quieres seguir con el dedo las preguntas de un árbol real?

Nuestro simulador muestra, paso a paso, las preguntas sí/no que un árbol de profundidad 5 se hace para tasar tu departamento en Lima.

Entrar al Simulador

01¿Qué es un Árbol de Decisión?

Un Árbol de Decisión es un modelo de aprendizaje supervisado no paramétrico que particiona recursivamente el espacio de características mediante reglas ortogonales condicionales (si X₁ ≤ umbral entonces ir a la izquierda, sino a la derecha).

A diferencia de los modelos basados en planos geométricos o pesos opacos, los árboles son modelos de caja blanca (white-box): cada predicción puede trazarse y auditarse visualmente desde el nodo raíz hasta la hoja terminal como si fuera un diagrama de flujo de lógica pura.

02Criterios de Partición: Impureza de Gini vs Entropía

En cada nodo, el algoritmo busca la variable y el umbral que maximicen la pureza de las divisiones resultantes. El criterio estándar en Scikit-Learn (algoritmo CART) es la Impureza de Gini:

Gini(D) = 1 - ∑ [ pᵢ² ]

Impureza de Gini = 0.0

Nodo perfectamente puro: el 100% de las muestras en ese subconjunto pertenecen a una sola clase. No se requieren más divisiones.

Ganancia de Información (Gain)

Es la reducción de impureza conseguida tras la división: Gain = Gini(Padre) - ∑ (N_hijo / N_padre) · Gini(Hijo).

03El Talón de Aquiles: Sobreajuste (Overfitting) y Poda

Si no se le imponen restricciones, un árbol de decisión crecerá hasta que cada hoja contenga exactamente 1 muestra, alcanzando 100% de precisión en entrenamiento pero fallando estrepitosamente en datos nuevos.

Hiperparámetros de Regularización Esenciales:
  • max_depth: Limita la altura máxima del árbol (evita reglas hiperespecíficas).
  • min_samples_split: Cantidad mínima de muestras requeridas para intentar una división.
  • min_samples_leaf: Mínimo de observaciones obligatorias en cada nodo terminal.

04Estrategias de Poda: Pre-Pruning vs Post-Pruning

Para controlar la tendencia destructiva del árbol hacia el sobreajuste (memorizar hojas con 1 sola muestra), aplicamos dos filosofías de regularización:

Pre-Poda (Early Stopping)

Frena el crecimiento del árbol antes de completarse fijando topes como max_depth=4 o exigiendo un mínimo de muestras por hoja min_samples_leaf=10. Rápido y fácil de sintonizar.

Post-Poda (Cost-Complexity Pruning)

Permite que el árbol crezca a profundidad completa y luego recorta recursivamente las ramas que aporten menor ganancia usando el parámetro de complejidad ccp_alpha.

05¿En qué situaciones conviene utilizar Árboles de Decisión?

Un Árbol de Decisión individual no es el modelo más potente del mundo moderno, pero es la herramienta rey indiscutida cuando se requiere comunicación y trazabilidad visual.

Cuándo SÍ conviene utilizarlos
  • Protocolos de Triaje y Flujos de Decisión Humana:

    En emergencias médicas hospitalarias, manuales de soporte técnico o aprobación de préstamos en ventanilla, se requiere un diagrama de flujo transparente que un operador humano pueda memorizar o imprimir en una hoja.

  • Datos heterogéneos sin escalado previo:

    Permite mezclar características numéricas continuas (ingresos en millones), variables discretas (edad en años) y categóricas sin necesidad de normalizar ni estandarizar escalas.

  • Exploración preliminar de interacciones:

    Permiten descubrir de un vistazo qué variables interactúan entre sí y cuáles son los umbrales de corte naturales del negocio antes de construir modelos más complejos.

Cuándo NO conviene utilizarlos como modelo único
  • Competencias y Producción de Alta Precisión:

    En datasets tabulares reales, un árbol individual casi siempre es superado por ensambles como Random Forest o XGBoost, que eliminan su varianza inherente.

  • Inestabilidad estructural ante pequeñas variaciones:

    Un árbol individual sufre de altísima sensibilidad al azar; cambiar solo 10 filas en el dataset de entrenamiento puede cambiar la raíz y generar un árbol con estructura totalmente distinta.

  • Fronteras diagonales suaves:

    Al particionar únicamente mediante cortes perpendiculares a los ejes (X_i ≤ c), para modelar una relación lineal diagonal suave y = x el árbol se ve obligado a crear una escalera infinita de micro-escalones ortogonales.

06Código Reproducible en Python

decision_tree_scratch.py (NumPy)
# 1. Cálculo de Impureza de Gini y división óptima desde cero
import numpy as np

def gini_impurity(y):
    classes, counts = np.unique(y, return_counts=True)
    probabilities = counts / len(y)
    return 1.0 - np.sum(probabilities ** 2)

def best_split(X, y):
    best_gain = -1.0
    split_idx, split_threshold = None, None
    current_gini = gini_impurity(y)
    
    n_samples, n_features = X.shape
    for feat_idx in range(n_features):
        thresholds = np.unique(X[:, feat_idx])
        for thresh in thresholds:
            left_mask = X[:, feat_idx] <= thresh
            right_mask = ~left_mask
            
            if np.sum(left_mask) == 0 or np.sum(right_mask) == 0:
                continue
                
            n_l, n_r = np.sum(left_mask), np.sum(right_mask)
            gini_l = gini_impurity(y[left_mask])
            gini_r = gini_impurity(y[right_mask])
            child_gini = (n_l / n_samples) * gini_l + (n_r / n_samples) * gini_r
            
            info_gain = current_gini - child_gini
            if info_gain > best_gain:
                best_gain = info_gain
                split_idx = feat_idx
                split_threshold = thresh
                
    return split_idx, split_threshold, best_gain

# Datos: [Horas_estudio, Simulacros] -> Aprobado (1) / Reprobado (0)
X = np.array([[2, 0], [4, 1], [6, 0], [8, 1], [10, 1]])
y = np.array([0, 0, 1, 1, 1])

feat, thresh, gain = best_split(X, y)
print(f"Mejor división: Feature {feat} <= {thresh} (Ganancia Gini: {gain:.4f})")
sklearn_decision_tree.py (Producción)
# 2. Árbol de Decisión con Scikit-Learn y visualización de reglas
from sklearn.tree import DecisionTreeClassifier, export_text
import numpy as np

# Datos: [Área m2, Habitaciones, Antigüedad años] -> Alto valor (1) / Estándar (0)
X = np.array([
    [45, 1, 15], [60, 2, 8], [95, 3, 2], 
    [120, 3, 1], [40, 1, 25], [110, 4, 3]
])
y = np.array([0, 0, 1, 1, 0, 1])

# Controlamos el sobreajuste con max_depth
clf = DecisionTreeClassifier(criterion='gini', max_depth=3, random_state=42)
clf.fit(X, y)

print("--- REGLAS DE DECISIÓN FORMAL DEL ÁRBOL ---")
tree_rules = export_text(clf, feature_names=['Área_m2', 'Habitaciones', 'Antigüedad'])
print(tree_rules)