Random Forest (bosque aleatorio) es uno de los algoritmos de machine learning más usados en la práctica: es fácil de entrenar, funciona bien con pocos ajustes y sirve tanto para clasificación como para regresión. En esta entrada veremos cómo funciona por dentro y cómo usarlo en Python con scikit-learn.

La idea: muchos árboles mejor que uno

Un árbol de decisión aprende reglas del tipo "si la edad es mayor a 30 y el ingreso menor a X, entonces…". Es fácil de interpretar, pero tiene un problema: tiende a sobreajustarse (memoriza los datos de entrenamiento y generaliza mal).

Random Forest resuelve esto entrenando muchos árboles distintos y combinando sus respuestas:

  • En clasificación, cada árbol vota y gana la clase más votada.
  • En regresión, se promedian las predicciones de todos los árboles.

Cada árbol por separado se equivoca, pero como se equivocan de formas distintas, al combinarlos los errores se compensan.

¿Cómo logra que los árboles sean distintos?

Con dos fuentes de aleatoriedad:

  1. Bagging (bootstrap aggregating): cada árbol se entrena con una muestra aleatoria con reemplazo del conjunto de datos. Algunas filas aparecen repetidas y otras (aprox. un 37 %) quedan fuera.
  2. Subconjunto aleatorio de variables: en cada división del árbol solo se considera un grupo aleatorio de columnas (por defecto, la raíz cuadrada del total en clasificación). Así se evita que todos los árboles usen siempre la misma variable dominante.

Las filas que quedaron fuera de cada árbol (out-of-bag) sirven además como un conjunto de validación "gratis".

Ejemplo en Python

Instala las dependencias:

pip install scikit-learn pandas

Usaremos el dataset de cáncer de mama que viene incluido en scikit-learn, donde hay que predecir si un tumor es maligno o benigno:

from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report
from sklearn.model_selection import train_test_split

# 1. Cargar datos
datos = load_breast_cancer(as_frame=True)
X, y = datos.data, datos.target

# 2. Separar entrenamiento y prueba
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# 3. Crear y entrenar el modelo
modelo = RandomForestClassifier(
    n_estimators=200,   # número de árboles
    oob_score=True,     # calcula la precisión con las muestras out-of-bag
    random_state=42,
    n_jobs=-1,          # usa todos los núcleos del procesador
)
modelo.fit(X_train, y_train)

# 4. Evaluar
predicciones = modelo.predict(X_test)
print(f"Precisión OOB:    {modelo.oob_score_:.3f}")
print(f"Precisión prueba: {accuracy_score(y_test, predicciones):.3f}")
print(classification_report(y_test, predicciones, target_names=datos.target_names))

Sin ajustar nada, el modelo suele superar el 95 % de precisión en este dataset.

¿Qué variables importan más?

Una ventaja de Random Forest es que indica qué variables aportaron más a las decisiones:

import pandas as pd

importancias = pd.Series(modelo.feature_importances_, index=X.columns)
print(importancias.sort_values(ascending=False).head(10))

Esto es muy útil para entender el problema y para descartar columnas que no aportan.

Hiperparámetros principales

Parámetro Qué controla Consejo
n_estimators Cantidad de árboles Más árboles = más estable, pero más lento. 100–500 suele bastar.
max_depth Profundidad máxima de cada árbol Limitarla reduce el sobreajuste.
max_features Variables consideradas en cada división "sqrt" para clasificación es un buen punto de partida.
min_samples_leaf Mínimo de muestras por hoja Subirlo (ej. 3–5) suaviza el modelo.
class_weight Peso de cada clase Usa "balanced" si una clase es mucho menos frecuente.

Para buscar la mejor combinación puedes usar GridSearchCV:

from sklearn.model_selection import GridSearchCV

parametros = {
    "n_estimators": [100, 300],
    "max_depth": [None, 10, 20],
    "min_samples_leaf": [1, 3, 5],
}
busqueda = GridSearchCV(
    RandomForestClassifier(random_state=42, n_jobs=-1),
    parametros,
    cv=5,
    scoring="accuracy",
)
busqueda.fit(X_train, y_train)
print(busqueda.best_params_, f"{busqueda.best_score_:.3f}")

Regresión

Para predecir un valor numérico (precios, demanda, temperaturas…) se usa RandomForestRegressor de la misma forma:

from sklearn.datasets import load_diabetes
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error

X, y = load_diabetes(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

regresor = RandomForestRegressor(n_estimators=300, random_state=42, n_jobs=-1)
regresor.fit(X_train, y_train)
print(f"Error absoluto medio: {mean_absolute_error(y_test, regresor.predict(X_test)):.1f}")

Ventajas y desventajas

Ventajas

  • Muy buen rendimiento con poca configuración.
  • Resistente al sobreajuste en comparación con un árbol solo.
  • No necesita escalar ni normalizar las variables.
  • Entrega la importancia de cada variable.
  • Se paraleliza fácilmente (n_jobs=-1).

Desventajas

  • Es menos interpretable que un único árbol.
  • Los modelos con muchos árboles ocupan memoria y predicen más lento.
  • En regresión no puede predecir valores fuera del rango visto en el entrenamiento.
  • En datos tabulares grandes, algoritmos de boosting como XGBoost o LightGBM suelen ganarle por algunos puntos.

Conclusión

Random Forest es una excelente primera opción para casi cualquier problema con datos tabulares: entrega un modelo sólido en pocas líneas y sirve como referencia para comparar modelos más complejos. Si recién empiezas con machine learning, es uno de los algoritmos que más vale la pena dominar.