28  Árboles de regresión lineal, ensambles y vecinos cercanos

Autor/a

Diego Villalba

Fecha de publicación

19 de mayo de 2026

Los árboles de decisión constituyen una familia de métodos de aprendizaje supervisado basada en reglas. A diferencia de un modelo lineal global, que intenta describir todo el conjunto de datos mediante una sola ecuación, un árbol divide el espacio de variables en regiones más pequeñas y ajusta una predicción simple en cada una. Esta idea es especialmente útil cuando la relación entre las variables explicativas y la variable respuesta no es lineal, cambia por zonas o involucra interacciones difíciles de especificar manualmente (Breiman et al. 1984; Hastie, Tibshirani, y Friedman 2009).

En problemas de regresión, el objetivo es predecir una variable numérica. Por ejemplo, podríamos estimar el precio de una laptop a partir de su memoria RAM, el tamaño de pantalla, el procesador o la marca; o bien estimar el precio de una vivienda con base en su área, ubicación y antigüedad. Un árbol de regresión construye reglas del tipo “si una variable cae por debajo de cierto umbral, sigue una rama; en caso contrario, sigue otra”. Al final de cada rama se encuentra una hoja, donde la predicción suele ser el promedio de las observaciones de entrenamiento que llegaron a esa región.

Este capítulo desarrolla la lógica de los árboles de regresión, su interpretación como funciones por partes, el criterio de error usado para elegir divisiones, la poda para controlar el sobreajuste y las métricas básicas de evaluación. Posteriormente se introducen métodos de ensamble basados en árboles, en particular bagging, random forests y boosting. Finalmente se presenta el algoritmo de vecinos más cercanos como contraste con los árboles: un método supervisado basado en distancia y aprendizaje perezoso.

1 De la regresión lineal a modelos por regiones

La regresión lineal múltiple modela una respuesta continua \(y\) como combinación lineal de variables explicativas \(x_1,\ldots,x_p\):

\[ y_i = \beta_0 + \beta_1 x_{i1}+\cdots+\beta_p x_{ip}+\varepsilon_i. \]

Su principal ventaja es la interpretabilidad de los coeficientes: cada \(\beta_j\) mide el cambio esperado en \(y\) ante un incremento unitario de \(x_j\), manteniendo constantes las demás variables. Sin embargo, esta estructura impone una forma funcional global. Cuando la relación entre \(X\) e \(y\) cambia en distintas regiones del espacio, una sola ecuación puede resultar demasiado rígida.

Los árboles de regresión responden a esta dificultad mediante particionamiento recursivo. En lugar de buscar una única superficie global, dividen el espacio de predictores en regiones y asignan una predicción constante a cada región. Esto produce un modelo no paramétrico, flexible e interpretable (James et al. 2021).

Nota

Definición. Un árbol de regresión es un modelo que particiona el espacio de predictores en regiones disjuntas \(R_1,\ldots,R_J\) y predice un valor constante \(c_h\) dentro de cada región: \[ \hat f(x)=\sum_{h=1}^{J} c_h\,\mathbb{I}(x\in R_h). \tag{1}\]

En esta expresión, \(x\) representa una nueva observación; \(R_h\) es una región del espacio de variables; \(c_h\) es el valor asignado a esa región, usualmente el promedio de las respuestas observadas dentro de ella; y \(\mathbb{I}(x\in R_h)\) es una función indicadora que vale uno si \(x\) pertenece a la región \(R_h\) y cero en caso contrario.

Nota

Definición. La función indicadora de una región \(R_h\) se define como: \[ \mathbb{I}(x\in R_h)= \begin{cases} 1, & \text{si } x\in R_h,\\ 0, & \text{si } x\notin R_h. \end{cases} \tag{2}\]

2 Clasificadores no lineales y modelos por partes

En problemas de clasificación, un clasificador lineal separa clases mediante hiperplanos. Si los datos son linealmente separables, esta estrategia puede ser suficiente. Sin embargo, en muchos problemas reales las fronteras entre clases son curvas, fragmentadas o dependen de interacciones entre variables. En estos casos existen dos alternativas: mantener un clasificador lineal y aceptar ciertos errores, o usar clasificadores no lineales capaces de aproximar fronteras más flexibles.

Una forma pedagógica de construir no linealidad es usar piezas lineales. La idea es dividir una clase en subclases o regiones locales y asignar a cada subregión un discriminante lineal. La frontera global resultante deja de ser un solo hiperplano y se convierte en una unión de segmentos o caras lineales. Esta lógica anticipa dos ideas que aparecen más adelante: los árboles, que dividen el espacio mediante cortes recursivos, y los vecinos cercanos, que llevan la idea local al extremo de tratar cada muestra como una referencia de decisión (Duda, Hart, y Stork 2001; Hastie, Tibshirani, y Friedman 2009).

Nota

Definición. Un clasificador lineal por partes asigna a cada clase \(\omega_i\) un conjunto de subclases \(\omega_i^1,\ldots,\omega_i^{\ell_i}\), cada una con un discriminante lineal \(g_i^\ell(x)\), y define el discriminante de la clase como el máximo local: \[ g_i(x)=\max_{\ell=1,\ldots,\ell_i} g_i^\ell(x),\qquad \hat y(x)=\arg\max_{i=1,\ldots,c} g_i(x). \tag{3}\]

Si se escribe \(g_i^\ell(x)=w_{i\ell}^{\top}x+w_{i\ell,0}\), cada subclase aporta una frontera lineal. El operador máximo selecciona la subregión de la clase que mejor explica el punto \(x\). Cuando el número de subclases aumenta, la frontera puede aproximar formas no lineales cada vez más complejas. No obstante, esta flexibilidad tiene un costo: se deben decidir cuántas subclases usar, cómo inicializarlas y cómo evitar que el modelo memorice ruido.

Desde esta perspectiva, los árboles de decisión construyen una aproximación por partes, pero con piezas constantes en regresión y fronteras alineadas con los ejes. KNN, por su parte, puede verse como un caso extremadamente local: en lugar de aprender subclases explícitas, conserva los ejemplos de entrenamiento y decide usando distancias.

3 Funciones por escalones

Un árbol de regresión produce una función por escalones. Para una sola variable \(x\), un modelo simple podría definirse como:

\[ \hat f(x)= \begin{cases} 100, & x<10,\\ 200, & 10\le x<20,\\ 300, & x\ge 20. \end{cases} \]

Este modelo no intenta ajustar una recta. En su lugar, divide el eje de \(x\) en intervalos y asigna una predicción constante a cada intervalo. En dos variables, las regiones suelen ser rectángulos; en \(p\) variables, se interpretan como hiperrectángulos. Por ejemplo, con edad, salario y experiencia, una regla podría ser:

\[ \text{edad}<30 \quad \text{y} \quad \text{salario}>5000. \]

Este tipo de reglas es fácil de leer, lo que explica la popularidad de los árboles en contextos donde la interpretación es importante. No obstante, también implica una limitación geométrica: las fronteras de decisión son paralelas a los ejes, por lo que algunas relaciones oblicuas o altamente correlacionadas pueden necesitar muchos cortes para aproximarse bien (Hastie, Tibshirani, y Friedman 2009).

4 Predicción dentro de una región

Una vez que el árbol define una región \(R_h\), la predicción óptima bajo pérdida cuadrática es el promedio de los valores reales dentro de esa región. Supongamos que en una región hay observaciones con respuestas \(y_1,\ldots,y_{n_h}\). La predicción constante \(c_h\) se elige minimizando la suma de errores cuadrados:

\[ \sum_{i:x_i\in R_h}(y_i-c_h)^2. \]

La solución es el promedio muestral.

Nota

Definición. La predicción de una hoja \(R_h\) en un árbol de regresión, bajo error cuadrático, es el promedio de las respuestas que caen en esa hoja: \[ \hat c_h = \frac{1}{|R_h|}\sum_{i:x_i\in R_h} y_i. \tag{4}\]

Por ejemplo, si una región contiene los valores reales \(20,40,100,120\), su predicción antes de dividir es:

\[ \hat c=\frac{20+40+100+120}{4}=70. \]

Si esa región se divide en dos grupos, \(R_1=\{20,40\}\) y \(R_2=\{100,120\}\), las nuevas predicciones son:

\[ \hat c_1=30,\qquad \hat c_2=110. \]

La división es útil porque cada grupo queda descrito por un promedio más representativo de sus valores.

5 Error total y criterio de división

El árbol decide sus cortes evaluando cuánto disminuye el error al dividir una región. Para regresión, el criterio más común es la suma de errores cuadrados dentro de las hojas, también conocida como residual sum of squares (RSS) (Breiman et al. 1984; James et al. 2021).

Nota

Definición. El error cuadrático total de un árbol con regiones \(R_1,\ldots,R_J\) es: \[ D(T)=\sum_{h=1}^{J}\sum_{i:x_i\in R_h}(y_i-\hat c_h)^2. \tag{5}\]

Cuando se propone dividir una región \(R\) en dos subregiones \(R_L\) y \(R_R\), el árbol compara el error antes y después de la división. El error después de dividir es:

\[ D_{\text{split}} = \sum_{i:x_i\in R_L}(y_i-\hat c_L)^2+ \sum_{i:x_i\in R_R}(y_i-\hat c_R)^2. \]

Nota

Definición. La ganancia de una división se define como la reducción de error producida por el corte: \[ \text{Gain}=D_{\text{antes}}-D_{\text{después}}. \tag{6}\]

Una división es buena si reduce mucho el error. Si la reducción es pequeña, el corte puede no justificar el aumento de complejidad. Durante el entrenamiento, el algoritmo prueba muchas divisiones candidatas: por ejemplo, cortes en edad, salario o experiencia; y dentro de cada variable, varios umbrales posibles. Se elige la división que produce la mayor reducción de error.

Criterio de división RSS — explorador interactivo
Arrastra el umbral de corte y observa cómo cambia el RSS antes y después de la partición

6 Particionamiento recursivo

El entrenamiento de un árbol se realiza de forma codiciosa. Primero se busca el mejor corte para todo el conjunto de entrenamiento. Luego, dentro de cada región resultante, se vuelve a buscar el mejor corte local. Este procedimiento se repite hasta que se cumple un criterio de parada: profundidad máxima, número mínimo de observaciones por hoja, reducción mínima de error o tamaño mínimo de nodo.

El algoritmo básico puede resumirse así:

  1. Comenzar con todos los datos en una sola región.
  2. Para cada variable y cada punto de corte candidato, calcular el error después de dividir.
  3. Elegir la división que más reduzca el error.
  4. Repetir el proceso dentro de cada subregión.
  5. Detener el crecimiento del árbol según reglas de control de complejidad.

El enfoque es eficiente y produce reglas interpretables, pero no garantiza encontrar el árbol globalmente óptimo. La búsqueda exacta del mejor árbol es combinatoriamente costosa, por lo que los algoritmos prácticos usan heurísticas codiciosas (Breiman et al. 1984).

7 Ejemplo manual: precio de laptops según RAM

Consideremos un conjunto de datos pequeño donde se desea predecir el precio de una laptop a partir de la memoria RAM.

Laptop RAM Precio real
A 4 GB 6500
B 4 GB 7200
C 8 GB 10500
D 8 GB 12000
E 16 GB 21000
F 16 GB 24000

Si no se divide el árbol, la predicción para todas las laptops es el promedio global:

\[ \bar y=\frac{6500+7200+10500+12000+21000+24000}{6}=13533.33. \]

El error sin dividir es:

\[ D_{\text{sin dividir}}=\sum_i(y_i-\bar y)^2=266{,}433{,}333.33. \]

Ahora se propone el corte:

\[ \text{RAM}<12. \]

Esto genera dos regiones:

\[ R_1=\{6500,7200,10500,12000\},\qquad R_2=\{21000,24000\}. \]

Las predicciones de cada hoja son:

\[ \hat c_1=\frac{6500+7200+10500+12000}{4}=9050, \]

\[ \hat c_2=\frac{21000+24000}{2}=22500. \]

El error después de dividir es:

\[ D_{\text{con división}}= (6500-9050)^2+(7200-9050)^2+(10500-9050)^2+(12000-9050)^2 +(21000-22500)^2+(24000-22500)^2. \]

Al calcular:

\[ D_{\text{con división}}=25{,}230{,}000. \]

La mejora relativa es:

\[ \frac{D_{\text{sin dividir}}-D_{\text{con división}}}{D_{\text{sin dividir}}} =\frac{266{,}433{,}333.33-25{,}230{,}000}{266{,}433{,}333.33} \approx 0.9053. \]

Por tanto, el corte reduce el error aproximadamente en \(90.53\%\). El árbol resultante tiene una regla clara: si la RAM es menor que 12 GB, predice 9050; si es mayor o igual que 12 GB, predice 22500.

8 Implementación en Python

El siguiente ejemplo reproduce la idea anterior con scikit-learn. Aunque el conjunto de datos es muy pequeño, permite observar cómo un árbol de regresión aprende divisiones por umbral.

Mostrar código
import numpy as np
import pandas as pd
from sklearn.tree import DecisionTreeRegressor, export_text
from sklearn.metrics import mean_squared_error, r2_score

# Datos de ejemplo
X = pd.DataFrame({
    "RAM_GB": [4, 4, 8, 8, 16, 16]
})
y = np.array([6500, 7200, 10500, 12000, 21000, 24000])

# Árbol pequeño de regresión
tree = DecisionTreeRegressor(max_depth=1, random_state=42)
tree.fit(X, y)

pred = tree.predict(X)

print(export_text(tree, feature_names=list(X.columns)))
print("Predicciones:", pred)
print("MSE:", mean_squared_error(y, pred))
print("R2:", r2_score(y, pred))
|--- RAM_GB <= 12.00
|   |--- value: [9050.00]
|--- RAM_GB >  12.00
|   |--- value: [22500.00]

Predicciones: [ 9050.  9050.  9050.  9050. 22500. 22500.]
MSE: 4205000.0
R2: 0.9053046415613661

El árbol de profundidad uno aprende un único corte. En un problema real se usaría una división entrenamiento-prueba o validación cruzada para estimar el desempeño fuera de muestra.

Mostrar código
import matplotlib.pyplot as plt

ram_grid = np.linspace(3, 17, 200).reshape(-1, 1)
pred_grid = tree.predict(pd.DataFrame(ram_grid, columns=["RAM_GB"]))

plt.figure()
plt.scatter(X["RAM_GB"], y, label="Datos reales")
plt.plot(ram_grid, pred_grid, label="Árbol de regresión")
plt.xlabel("RAM (GB)")
plt.ylabel("Precio")
plt.legend()
plt.show()

9 Sobreajuste y poda

Un árbol puede seguir dividiendo hasta que cada hoja contenga muy pocas observaciones. En el extremo, podría memorizar los datos de entrenamiento. Esto reduce el error dentro de la muestra, pero aumenta el riesgo de fallar con datos nuevos. Este fenómeno se conoce como sobreajuste.

Para evitarlo, se controla la complejidad del árbol. Una estrategia clásica es la poda por costo-complejidad, que penaliza el número de hojas del árbol (Breiman et al. 1984; scikit-learn developers 2025).

Nota

Definición. El criterio de costo-complejidad penaliza el error total del árbol más un término proporcional al número de hojas: \[ C_{\alpha}(T)=\sum_{h=1}^{J}D_h+\alpha J. \tag{7}\]

Aquí \(D_h\) es el error de la hoja \(h\), \(J\) es el número de hojas y \(\alpha\ge 0\) controla la penalización por complejidad. Si \(\alpha\) es pequeño, se permite un árbol más grande; si \(\alpha\) es grande, se castigan más las divisiones.

Consideremos dos árboles:

Modelo Error Número de hojas \(J\) \(\alpha\) Costo total
Árbol pequeño 500 3 20 \(500+20(3)=560\)
Árbol grande 300 20 20 \(300+20(20)=700\)

Aunque el árbol grande tiene menor error de entrenamiento, su costo total es mayor debido a la penalización por complejidad. Bajo este criterio, se preferiría el árbol pequeño.

En scikit-learn, este control puede implementarse mediante el parámetro ccp_alpha.

Mostrar código
from sklearn.model_selection import train_test_split
from sklearn.datasets import fetch_california_housing
from sklearn.metrics import mean_absolute_error

housing = fetch_california_housing(as_frame=True)
X = housing.data
y = housing.target

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, random_state=42
)

for alpha in [0.0, 0.001, 0.01, 0.05]:
    model = DecisionTreeRegressor(random_state=42, ccp_alpha=alpha)
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    print({
        "ccp_alpha": alpha,
        "n_leaves": model.get_n_leaves(),
        "MAE": mean_absolute_error(y_test, y_pred),
        "R2": r2_score(y_test, y_pred)
    })
{'ccp_alpha': 0.0, 'n_leaves': np.int64(14853), 'MAE': 0.4647446201550388, 'R2': 0.6066030019129263}
{'ccp_alpha': 0.001, 'n_leaves': np.int64(98), 'MAE': 0.45694597870846365, 'R2': 0.6782893932519991}
{'ccp_alpha': 0.01, 'n_leaves': np.int64(11), 'MAE': 0.5813661215307218, 'R2': 0.5457586289530623}
{'ccp_alpha': 0.05, 'n_leaves': np.int64(5), 'MAE': 0.6348311418653407, 'R2': 0.47820743421206036}
Profundidad del árbol y sobreajuste
Aumenta la profundidad máxima y observa cómo el árbol memoriza los datos de entrenamiento

10 Evaluación de árboles de regresión

En regresión, una métrica frecuente es el coeficiente de determinación \(R^2\). Este compara el error del modelo con el error de un modelo base que siempre predice el promedio de la variable respuesta.

Nota

Definición. El coeficiente de determinación \(R^2\) se define como: \[ R^2=1-\frac{SSE}{SS_{TOT}}, \] con \[ SSE=\sum_i(y_i-\hat y_i)^2, \qquad SS_{TOT}=\sum_i(y_i-\bar y)^2. \tag{8}\]

Un valor \(R^2=0.90\) indica que el modelo explica aproximadamente el 90% de la variabilidad de la respuesta respecto al promedio. Un valor cercano a cero indica que el modelo no mejora sustancialmente frente a predecir siempre la media. En conjuntos de prueba, un \(R^2\) negativo también es posible: significa que el modelo generaliza peor que el predictor promedio.

Además de \(R^2\), se suelen reportar el error absoluto medio (MAE), el error cuadrático medio (MSE) y la raíz del error cuadrático medio (RMSE). La selección de métrica depende del problema. Si se desea penalizar mucho los errores grandes, RMSE puede ser adecuado; si se busca una medida más robusta ante valores extremos, MAE suele ser más interpretable.

11 Ventajas y limitaciones de los árboles

Los árboles de regresión tienen varias ventajas. Son fáciles de entender porque se parecen a diagramas de decisión; producen reglas explícitas; pueden capturar relaciones no lineales e interacciones; requieren poca preparación de variables; y pueden trabajar con distintos criterios de error (James et al. 2021). Algunos algoritmos de árboles también incorporan estrategias para tratar datos faltantes, como divisiones sustitutas o surrogate splits (Breiman et al. 1984).

Sus limitaciones también son importantes. Primero, tienden a sobreajustarse si crecen demasiado. Segundo, sus particiones rectangulares pueden ser ineficientes cuando la verdadera relación entre variables es suave u oblicua. Tercero, son inestables: pequeños cambios en los datos pueden producir árboles muy distintos. Cuarto, pueden ser sensibles al ruido y a valores atípicos. Finalmente, si llegan nuevos datos, normalmente se reentrena el árbol completo.

Estas debilidades motivan el uso de métodos de ensamble, donde se combinan muchos árboles para obtener predicciones más estables y precisas.

12 Bagging: agregación por bootstrap

Bagging, abreviatura de bootstrap aggregating, fue propuesto por Breiman como una técnica para mejorar la estabilidad y precisión de predictores inestables (Breiman 1996). La idea consiste en entrenar muchos modelos sobre muestras bootstrap del conjunto original y combinar sus predicciones.

Nota

Definición. Una muestra bootstrap de tamaño \(n\) se obtiene seleccionando \(n\) observaciones con reemplazo a partir del conjunto de entrenamiento original. \[ \mathcal{D}^{*(b)}=\{(x_1^{*(b)},y_1^{*(b)}),\ldots,(x_n^{*(b)},y_n^{*(b)})\}. \tag{9}\]

El procedimiento general es:

  1. Generar muchas muestras bootstrap del conjunto de entrenamiento.
  2. Entrenar un árbol independiente en cada muestra.
  3. Combinar las predicciones de todos los árboles.

En regresión, la combinación suele ser el promedio:

Nota

Definición. La predicción bagging para regresión es el promedio de las predicciones de \(B\) modelos entrenados sobre muestras bootstrap: \[ \hat f_{bag}(x)=\frac{1}{B}\sum_{b=1}^{B}\hat f^{*(b)}(x). \tag{10}\]

Bagging reduce la varianza sin aumentar demasiado el sesgo. Es especialmente útil con árboles de decisión, porque los árboles individuales pueden variar mucho ante cambios pequeños en los datos.

Mostrar código
from sklearn.ensemble import BaggingRegressor

bag = BaggingRegressor(
    estimator=DecisionTreeRegressor(random_state=42),
    n_estimators=100,
    random_state=42,
    n_jobs=-1
)

bag.fit(X_train, y_train)
y_pred_bag = bag.predict(X_test)

print("MAE bagging:", mean_absolute_error(y_test, y_pred_bag))
print("R2 bagging:", r2_score(y_test, y_pred_bag))
MAE bagging: 0.32921646063953486
R2 bagging: 0.8074171978455695

13 Random forests

Random forest extiende bagging introduciendo aleatoriedad adicional en la construcción de cada árbol. Además de entrenar cada árbol con una muestra bootstrap, en cada división se considera solo un subconjunto aleatorio de variables candidatas (Breiman 2001). Esto disminuye la correlación entre árboles y mejora la reducción de varianza.

Nota

Definición. Un random forest es un ensamble de árboles entrenados sobre muestras bootstrap, donde cada división se elige considerando solo un subconjunto aleatorio de variables. \[ \hat f_{RF}(x)=\frac{1}{B}\sum_{b=1}^{B}\hat f_b(x). \tag{11}\]

El modelo conserva parte de la interpretabilidad de los árboles, por ejemplo mediante medidas de importancia de variables, pero su estructura global ya no se resume en un único diagrama. A cambio, suele ofrecer mejor desempeño predictivo y menor inestabilidad.

Mostrar código
from sklearn.ensemble import RandomForestRegressor

rf = RandomForestRegressor(
    n_estimators=300,
    max_features="sqrt",
    random_state=42,
    n_jobs=-1
)

rf.fit(X_train, y_train)
y_pred_rf = rf.predict(X_test)

print("MAE random forest:", mean_absolute_error(y_test, y_pred_rf))
print("R2 random forest:", r2_score(y_test, y_pred_rf))

importances = pd.Series(rf.feature_importances_, index=X_train.columns)
importances.sort_values(ascending=False).head(10)
MAE random forest: 0.32785055025839827
R2 random forest: 0.8157534169907247
MedInc        0.355768
Latitude      0.133573
Longitude     0.131074
AveOccup      0.123788
AveRooms      0.119190
HouseAge      0.056062
AveBedrms     0.044804
Population    0.035741
dtype: float64

14 Boosting

Boosting también combina varios modelos, pero a diferencia de bagging, los entrena de forma secuencial. Cada nuevo modelo intenta corregir los errores cometidos por los modelos anteriores. La intuición es construir un predictor fuerte a partir de muchos aprendices débiles (Freund y Schapire 1997; Schapire 1990).

En clasificación, algunos métodos de boosting asignan mayor peso a las observaciones mal clasificadas. En regresión, una forma muy influyente es gradient boosting, donde cada nuevo árbol se ajusta a los residuos o, más generalmente, a la dirección de descenso del gradiente de una función de pérdida (Friedman 2001).

Nota

Definición. En gradient boosting para regresión con pérdida cuadrática, el modelo se construye aditivamente: \[ F_M(x)=F_0(x)+\sum_{m=1}^{M}\nu h_m(x), \] donde cada \(h_m\) se ajusta a los residuos del modelo anterior y \(\nu\) es la tasa de aprendizaje. $$ {#eq-gradient-boosting}

El procedimiento conceptual es:

  1. Entrenar un primer modelo simple.
  2. Calcular los errores o residuos.
  3. Entrenar un nuevo modelo para explicar esos errores.
  4. Repetir el proceso varias veces.
  5. Combinar los modelos, usualmente con pesos o una tasa de aprendizaje.

Boosting puede alcanzar alta precisión, pero suele ser más sensible al ruido, a valores atípicos y al sobreajuste. Por ello requiere controlar hiperparámetros como número de estimadores, profundidad de los árboles, tasa de aprendizaje y regularización.

Mostrar código
from sklearn.ensemble import GradientBoostingRegressor

gb = GradientBoostingRegressor(
    n_estimators=300,
    learning_rate=0.05,
    max_depth=3,
    random_state=42
)

gb.fit(X_train, y_train)
y_pred_gb = gb.predict(X_test)

print("MAE gradient boosting:", mean_absolute_error(y_test, y_pred_gb))
print("R2 gradient boosting:", r2_score(y_test, y_pred_gb))
MAE gradient boosting: 0.355833880633663
R2 gradient boosting: 0.7956950818163337

Entre las implementaciones modernas de boosting se encuentran XGBoost, LightGBM y CatBoost. Estas bibliotecas agregan optimizaciones computacionales y regularización avanzada, y son comunes en competencias y aplicaciones tabulares de alto rendimiento (Chen y Guestrin 2016; Ke et al. 2017; Prokhorenkova et al. 2018).

15 Bagging frente a boosting

Bagging y boosting combinan modelos, pero responden a problemas distintos.

Característica Bagging Boosting
Entrenamiento Modelos independientes Modelos secuenciales
Objetivo principal Reducir varianza Reducir sesgo y mejorar precisión
Manejo de errores Las muestras se tratan de forma similar Se enfoca en errores previos
Paralelización Naturalmente paralelizable Menos paralelizable por dependencia secuencial
Ruido y atípicos Más robusto Más sensible
Ejemplos Bagging, Random Forest AdaBoost, Gradient Boosting, XGBoost, LightGBM, CatBoost

Como regla práctica, bagging es recomendable cuando el modelo base tiene alta varianza y tendencia al sobreajuste, como ocurre con árboles profundos. Boosting es útil cuando se busca mayor precisión y el modelo base todavía subajusta patrones relevantes, aunque debe regularizarse cuidadosamente.

16 Clasificación del vecino más cercano

El algoritmo del vecino más cercano pertenece a otra familia de métodos supervisados. En lugar de construir reglas explícitas como un árbol, almacena los datos de entrenamiento y clasifica un nuevo punto según las observaciones más parecidas. Por ello se considera un método basado en memoria o lazy learning: el “aprendizaje” ocurre principalmente al guardar los casos, mientras que el esfuerzo computacional se desplaza al momento de predecir (Cover y Hart 1967; Duda, Hart, y Stork 2001).

Sea un conjunto de entrenamiento

\[ S_N=\{(x_1,\theta_1),(x_2,\theta_2),\ldots,(x_N,\theta_N)\}, \]

donde \(x_i\in\mathbb{R}^p\) es el vector de atributos y \(\theta_i\in\{1,\ldots,c\}\) es la etiqueta de clase. Dada una métrica o función de distancia \(d(x,z)\), el clasificador de vecino más cercano busca el punto de entrenamiento más próximo a una nueva observación \(x\).

Nota

Definición. En el clasificador de vecino más cercano, una nueva observación \(x\) recibe la clase de la observación de entrenamiento más cercana bajo una métrica de distancia \(d\): \[ \hat y(x)=\theta_{i^*},\qquad i^*=\arg\min_{i=1,\ldots,N} d(x,x_i). \tag{12}\]

También puede formularse mediante funciones discriminantes. Para cada clase \(\omega_j\), se calcula la distancia mínima entre \(x\) y los ejemplos de esa clase; se asigna la clase cuya distancia mínima sea menor.

Nota

Definición. El discriminante de distancia mínima para la clase \(\omega_j\) es: \[ g_j(x)=\min_{i:\theta_i=j} d(x,x_i),\qquad \hat y(x)=\arg\min_{j=1, \ldots,c} g_j(x). \tag{13}\]

Esta formulación muestra la conexión con los clasificadores por partes: si cada muestra de entrenamiento se trata como una subclase, entonces la regla de decisión se reduce a escoger la muestra más cercana.

17 Métricas de distancia para vecinos cercanos

La elección de la distancia es crucial. KNN no “entiende” directamente el significado semántico de las variables; solo compara puntos mediante una métrica. Por eso, variables medidas en escalas grandes pueden dominar la decisión si no se normalizan o estandarizan. Además, distintas métricas inducen geometrías distintas: la distancia euclidiana produce vecindades esféricas, mientras que la distancia Manhattan produce vecindades con forma de rombo en dos dimensiones.

Nota

Definición. La distancia de Minkowski de orden \(s\geq 1\) entre \(x,z\in\mathbb{R}^p\) se define como: \[ d_s(x,z)=\left(\sum_{j=1}^{p}|x_j-z_j|^s\right)^{1/s}. \tag{14}\]

Casos particulares importantes son la distancia Manhattan (\(s=1\)) y la distancia euclidiana (\(s=2\)).

Nota

Definición. La distancia Manhattan o taxicab entre \(x\) y \(z\) es: \[ d_1(x,z)=\sum_{j=1}^{p}|x_j-z_j|. \tag{15}\]

Nota

Definición. La distancia euclidiana entre \(x\) y \(z\) es: \[ d_2(x,z)=\sqrt{\sum_{j=1}^{p}(x_j-z_j)^2}. \tag{16}\]

Otra opción es la distancia de Chebyshev, que mide la máxima diferencia coordenada a coordenada.

Nota

Definición. La distancia de Chebyshev entre \(x\) y \(z\) es: \[ d_{\infty}(x,z)=\max_{j=1, \ldots,p}|x_j-z_j|. \tag{17}\]

También se usan distancias cuadráticas ponderadas, útiles cuando las variables tienen distinta escala o correlación. Si \(Q\) es una matriz simétrica definida positiva, entonces

Nota

Definición. Una distancia cuadrática ponderada entre \(x\) y \(z\) puede escribirse como: \[ d_Q(x,z)=(x-z)^{\top}Q(x-z). \tag{18}\]

Un caso relevante es la distancia de Mahalanobis, donde \(Q=\Sigma^{-1}\) y \(\Sigma\) es la matriz de covarianza. Esta distancia corrige por escala y correlación entre variables (Duda, Hart, y Stork 2001).

Mostrar código
import numpy as np

x = np.array([30, 25])
z = np.array([28, 24])

manhattan = np.sum(np.abs(x - z))
euclidean = np.sqrt(np.sum((x - z)**2))
chebyshev = np.max(np.abs(x - z))

print({
    "Manhattan": manhattan,
    "Euclidiana": euclidean,
    "Chebyshev": chebyshev
})
{'Manhattan': np.int64(3), 'Euclidiana': np.float64(2.23606797749979), 'Chebyshev': np.int64(2)}
Bola unitaria de Minkowski — explorador interactivo
Arrastra p para ver cómo cambia la forma de la bola: diamante (p=1), círculo (p=2), cuadrado (p→∞)

18 De 1-NN a k-NN

La regla 1-NN puede generar regiones de clasificación muy fragmentadas, pues una sola observación ruidosa puede modificar la frontera local. Para reducir esa sensibilidad, se generaliza el método considerando los \(k\) vecinos más cercanos. En clasificación, cada vecino vota por su clase; en regresión, se promedian sus respuestas.

Nota

Definición. En \(k\)-NN para clasificación, si \(N_k(x)\) es el conjunto de índices de los \(k\) vecinos más cercanos de \(x\), el discriminante de la clase \(j\) es el número de vecinos que pertenecen a esa clase: \[ g_j(x)=\sum_{i\in N_k(x)}\mathbb{I}(\theta_i=j),\qquad \hat y(x)=\arg\max_{j=1, \ldots,c}g_j(x). \tag{19}\]

Nota

Definición. En \(k\)-NN para regresión, la predicción es el promedio de las respuestas de los \(k\) vecinos más cercanos: \[ \hat f(x)=\frac{1}{k}\sum_{i\in N_k(x)}y_i. \tag{20}\]

La elección de \(k\) controla el equilibrio sesgo-varianza. Con \(k=1\), el modelo tiene bajo sesgo local, pero alta varianza: puede adaptarse demasiado a puntos individuales. Con un \(k\) grande, la frontera se suaviza y la varianza disminuye, pero aumenta el sesgo porque se promedian observaciones que pueden pertenecer a regiones distintas (Hastie, Tibshirani, y Friedman 2009). En aplicaciones prácticas, \(k\) suele elegirse mediante validación cruzada. Para clasificación binaria, a menudo se usan valores impares de \(k\) para reducir empates.

Mostrar código
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score, classification_report
import pandas as pd

clientes = pd.DataFrame({
    "edad": [25, 28, 32, 35, 29, 31, 40, 22],
    "ingreso": [20, 24, 26, 30, 23, 27, 35, 18],
    "compra": ["No compra", "No compra", "Compra", "Compra", "No compra", "Compra", "Compra", "No compra"]
})

X_cls = clientes[["edad", "ingreso"]]
y_cls = clientes["compra"]

knn = Pipeline([
    ("scaler", StandardScaler()),
    ("model", KNeighborsClassifier())
])

param_grid = {"model__n_neighbors": [1, 3, 5]}
search = GridSearchCV(knn, param_grid=param_grid, cv=2)
search.fit(X_cls, y_cls)

nuevo_cliente = pd.DataFrame({"edad": [30], "ingreso": [25]})
print("Mejor k:", search.best_params_)
print("Predicción:", search.predict(nuevo_cliente))
Mejor k: {'model__n_neighbors': 1}
Predicción: ['No compra']
k-NN clasificador — explorador interactivo
Haz clic en el canvas para consultar un punto; ajusta k para ver cómo cambia la frontera de decisión
Haz clic en el canvas para clasificar un punto

19 Error asintótico de vecinos cercanos

Una razón histórica de la importancia de NN es que posee garantías teóricas simples. En el límite de muchas observaciones independientes e idénticamente distribuidas, el error asintótico de 1-NN está acotado por el error de Bayes, que es el menor error posible si se conocieran las distribuciones verdaderas de las clases (Cover y Hart 1967).

Nota

Definición. Si \(P^*\) es el error de Bayes y \(P_1\) es el error asintótico de 1-NN con \(c\) clases, entonces: \[ P^*\leq P_1\leq P^*\left(2-\frac{c}{c-1}P^*\right). \tag{21}\]

Como consecuencia, para dos o más clases se suele resumir la cota como \(P_1\leq 2P^*\). Es decir, bajo los supuestos del resultado, 1-NN no es arbitrariamente malo en el límite: su error asintótico es, a lo más, aproximadamente el doble del error óptimo de Bayes.

Para \(k\)-NN, si \(N\to\infty\), \(k\to\infty\) y \(k/N\to 0\), el método puede aproximar el rendimiento óptimo de Bayes. La condición \(k/N\to 0\) expresa que el vecindario debe crecer en número de puntos, pero seguir siendo local en relación con el tamaño total de la muestra (Stone 1977; Hastie, Tibshirani, y Friedman 2009).

Nota

Definición. Una condición clásica de consistencia para \(k\)-NN es: \[ N\to\infty,\qquad k\to\infty,\qquad \frac{k}{N}\to 0. \tag{22}\]

Estas conclusiones dependen de que los vecinos cercanos sean realmente cercanos en el espacio de atributos. En alta dimensión, esta condición puede fallar: incluso el vecino más cercano puede quedar lejos en términos geométricos. Este fenómeno forma parte de la llamada maldición de la dimensionalidad.

20 Maldición de la dimensionalidad

KNN funciona mejor cuando la dimensión efectiva del problema no es demasiado alta y existe una noción de cercanía significativa. En espacios de alta dimensión, las distancias tienden a concentrarse: la diferencia entre el vecino más cercano y el más lejano puede volverse pequeña en relación con la escala total. Como resultado, la noción de “vecino” pierde poder discriminativo y se requieren muchas más muestras para cubrir el espacio (Hastie, Tibshirani, y Friedman 2009; Bellman 1961).

Nota

Definición. En un hipercubo unitario de dimensión \(p\), una región con fracción lineal \(r\) en cada coordenada ocupa una fracción de volumen: \[ V(r,p)=r^p. \tag{23}\]

Esta expresión muestra por qué la dimensión importa. Si \(r=0.1\) y \(p=10\), el volumen relativo es \(10^{-10}\). Para cubrir localmente un espacio de alta dimensión se necesitaría una cantidad enorme de datos. Por ello, antes de aplicar KNN conviene considerar selección de variables, reducción de dimensionalidad, escalamiento adecuado y validación cuidadosa.

21 Métodos mejorados para vecinos cercanos

El método NN básico tiene tres limitaciones principales: debe almacenar todos los datos, debe comparar una consulta contra muchas observaciones y es sensible al ruido. Existen variantes que atacan estas dificultades.

21.1 Búsqueda eficiente: branch and bound

Los algoritmos de búsqueda rápida reducen el tiempo de predicción mediante preparación fuera de línea. La idea general es organizar las muestras en una estructura jerárquica y descartar regiones completas cuando no pueden contener al vecino más cercano. Esta lógica aparece en métodos branch and bound, árboles k-d y árboles de bolas (Friedman, Bentley, y Finkel 1977; Fukunaga y Narendra 1975).

Supongamos que un nodo \(p\) contiene un subconjunto de muestras \(\mathcal{X}_p\), con centro \(M_p\) y radio \(r_p\) definido como la máxima distancia desde el centro a una muestra del nodo.

Nota

Definición. Para un nodo \(p\) con muestras \(\mathcal{X}_p\), su centro y radio pueden definirse como: \[ M_p=\frac{1}{N_p}\sum_{x_i\in\mathcal{X}_p}x_i, \qquad r_p=\max_{x_i\in\mathcal{X}_p}d(x_i,M_p). \tag{24}\]

Si \(B\) es la mejor distancia encontrada hasta el momento para una consulta \(x\), se puede descartar un nodo cuando, por desigualdad triangular, ningún punto del nodo puede mejorar esa distancia. Una forma intuitiva de la regla es: si el centro del nodo está demasiado lejos de \(x\) en comparación con su radio, no vale la pena explorar ese nodo.

Nota

Definición. Una regla de descarte por cota inferior para un nodo \(p\) es: \[ d(x,M_p)-r_p>B. \tag{25}\]

Si se cumple Ec. 28.25, entonces incluso el punto más favorable dentro del nodo estaría a una distancia mayor que \(B\), por lo que el nodo puede descartarse.

21.2 Edición de vecinos cercanos

La edición de vecinos cercanos busca eliminar muestras ambiguas o ruidosas, especialmente en regiones donde las clases se traslapan. La intuición es que ciertos puntos mal etiquetados o ubicados en zonas de conflicto pueden fragmentar la frontera de decisión y perjudicar la generalización (Wilson 1972).

Un procedimiento típico consiste en preclasificar cada muestra usando sus vecinos; si una muestra es clasificada incorrectamente por el resto del conjunto, se marca como candidata a eliminar. Este proceso puede repetirse varias rondas si se cuenta con suficientes datos. La edición puede mejorar robustez, aunque también puede eliminar casos difíciles pero legítimos, por lo que debe evaluarse con validación.

Nota

Definición. La edición por preclasificación elimina una muestra \((x_i,y_i)\) si su etiqueta no coincide con la predicción obtenida al clasificarla usando el conjunto de entrenamiento sin esa muestra: \[ (x_i,y_i)\text{ se elimina si } \hat y_{-i}(x_i)\neq y_i. \tag{26}\]

21.3 Condensed nearest neighbor

El método condensed nearest neighbor busca reducir memoria y cómputo conservando solo un subconjunto representativo de muestras (Hart 1968). Se separa el conjunto original en dos partes: un conjunto almacenado \(\mathcal{S}\) y un conjunto restante \(\mathcal{G}\). Se comienza con pocas muestras en \(\mathcal{S}\); luego se revisan las muestras de \(\mathcal{G}\). Si una muestra se clasifica correctamente usando \(\mathcal{S}\), no se agrega; si se clasifica mal, se incorpora a \(\mathcal{S}\). Al final, solo \(\mathcal{S}\) se usa para clasificar.

Nota

Definición. El conjunto condensado \(\mathcal{S}\) busca ser un subconjunto del entrenamiento tal que el clasificador 1-NN construido con \(\mathcal{S}\) preserve, aproximadamente, las decisiones obtenidas con el conjunto completo: \[ \mathcal{S}\subseteq S_N, \qquad \hat y_{\mathcal{S}}(x_i)\approx \hat y_{S_N}(x_i). \tag{27}\]

Mostrar código
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import make_moons
from sklearn.model_selection import cross_val_score
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

X_demo, y_demo = make_moons(n_samples=300, noise=0.25, random_state=42)

scores = []
for k in [1, 3, 5, 11, 21, 51]:
    model = Pipeline([
        ("scaler", StandardScaler()),
        ("knn", KNeighborsClassifier(n_neighbors=k))
    ])
    acc = cross_val_score(model, X_demo, y_demo, cv=5, scoring="accuracy").mean()
    scores.append({"k": k, "accuracy_cv": acc})

pd.DataFrame(scores)
k accuracy_cv
0 1 0.906667
1 3 0.923333
2 5 0.920000
3 11 0.926667
4 21 0.916667
5 51 0.900000

22 Cuándo usar KNN

KNN es una buena opción cuando el tamaño de muestra es razonable, la dimensión no es demasiado alta, las variables pueden escalarse de forma significativa y se desea una decisión basada en casos similares. Su interpretación es natural: “este punto se clasifica así porque se parece a estos ejemplos”. Sin embargo, no es ideal cuando hay millones de observaciones, demasiadas variables irrelevantes, datos muy ruidosos o necesidad de predicción en tiempo real sin estructuras de búsqueda especializadas.

23 Comparación conceptual: árboles y vecinos cercanos

Los árboles y KNN son métodos no lineales, pero su lógica es distinta. Los árboles construyen particiones explícitas mediante reglas jerárquicas; KNN define vecindades alrededor del punto a predecir. Los árboles generan modelos relativamente rápidos al momento de predecir, porque basta recorrer una ruta desde la raíz hasta una hoja. KNN puede ser más costoso en predicción, porque debe calcular distancias con respecto a muchos puntos de entrenamiento, salvo que se usen estructuras de búsqueda eficientes.

Desde el punto de vista pedagógico, ambos métodos ayudan a entender que el aprendizaje supervisado no se reduce a ajustar rectas. Un modelo puede aproximar una función mediante regiones constantes, mediante promedios locales o mediante combinaciones de muchos modelos simples.

24 Buenas prácticas de modelado

Para usar árboles, ensambles o KNN en un flujo reproducible de ciencia de datos, conviene seguir algunas reglas:

  1. Separar datos de entrenamiento, validación y prueba, o usar validación cruzada.
  2. Comparar contra modelos base simples, como predecir siempre el promedio en regresión.
  3. Reportar métricas adecuadas al problema, no solo una métrica global.
  4. Controlar hiperparámetros con validación, no con el conjunto de prueba.
  5. Documentar semillas aleatorias, versiones de paquetes y criterios de evaluación.
  6. Interpretar el modelo considerando sus supuestos geométricos: regiones rectangulares en árboles, distancias en KNN y reducción de varianza o sesgo en ensambles.

El siguiente ejemplo muestra una comparación breve entre árbol individual, random forest y gradient boosting.

Mostrar código
from sklearn.model_selection import cross_validate

models = {
    "Árbol": DecisionTreeRegressor(random_state=42),
    "Random Forest": RandomForestRegressor(n_estimators=200, random_state=42, n_jobs=-1),
    "Gradient Boosting": GradientBoostingRegressor(random_state=42)
}

results = []
for name, model in models.items():
    cv = cross_validate(
        model,
        X,
        y,
        cv=5,
        scoring={"r2": "r2", "neg_mae": "neg_mean_absolute_error"},
        n_jobs=-1
    )
    results.append({
        "modelo": name,
        "R2_promedio": cv["test_r2"].mean(),
        "MAE_promedio": -cv["test_neg_mae"].mean()
    })

pd.DataFrame(results).sort_values("R2_promedio", ascending=False)
modelo R2_promedio MAE_promedio
2 Gradient Boosting 0.669829 0.471677
1 Random Forest 0.654549 0.464681
0 Árbol 0.344065 0.620737

25 Conclusiones

Los árboles de regresión son modelos supervisados que reemplazan una ecuación global por una colección de reglas locales. Su predicción es constante dentro de cada región y se calcula como el promedio de las observaciones que caen en la hoja correspondiente. El entrenamiento se basa en particionamiento recursivo: se prueban cortes y se elige aquel que reduce más el error, usualmente medido como suma de cuadrados.

Su principal fortaleza es la interpretabilidad, pero también presentan riesgos: sobreajuste, sensibilidad al ruido, inestabilidad y fronteras rectangulares. La poda y el criterio de costo-complejidad ayudan a controlar árboles individuales. Los métodos de ensamble, como bagging, random forests y boosting, buscan superar estas limitaciones combinando muchos árboles. Bagging reduce varianza mediante entrenamiento paralelo sobre muestras bootstrap; boosting entrena modelos secuencialmente para corregir errores y suele obtener alta precisión bajo una buena regularización.

Finalmente, el vecino más cercano muestra otra forma de razonamiento no lineal: predecir a partir de casos similares. Mientras los árboles dividen el espacio mediante reglas, KNN usa distancias. En conjunto, estos métodos ofrecen una introducción poderosa al modelado predictivo moderno y preparan el terreno para técnicas más avanzadas de aprendizaje automático.