Curso
En el amplio campo del aprendizaje automático, afrontar conjuntos de datos extensos y complejos para encontrar los mejores hiperparámetros durante el entrenamiento es un reto habitual.
Los métodos convencionales, como la búsqueda aleatoria y en rejilla, pueden resultar lentos e ineficientes, sobre todo cuando trabajas con arquitecturas complejas o datos a gran escala.
Aquí es donde un enfoque más inteligente y adaptativo como la optimización bayesiana se vuelve crucial para la optimización de hiperparámetros.
El primer objetivo de este artículo es explicar qué es la optimización bayesiana y ofrecerte una base teórica sólida. Sin embargo, antes de entrar en el concepto, conviene repasar los distintos métodos de optimización de hiperparámetros que tenemos a nuestro alcance.
La segunda parte del artículo se centra en una implementación práctica de los conceptos clave con el lenguaje de programación Python. En la última sección, verás cómo aprovechar la optimización bayesiana para el ajuste de hiperparámetros de un modelo de aprendizaje automático.
¿Qué es la optimización bayesiana?
Antes de definir la optimización bayesiana, veamos de forma general los cuatro principales métodos de optimización de hiperparámetros con ejemplos sencillos:
- Búsqueda manual
- Búsqueda aleatoria
- Búsqueda en rejilla, y
- Optimización bayesiana.
Búsqueda manual
Es el método más básico, basado en la experiencia, la intuición o el ensayo y error. Suele exigir mucho tiempo y depende en gran medida de la pericia de quien lo aplica.
Por ejemplo, una pastelera con experiencia fija la temperatura del horno y el tiempo de horneado según su bagaje y criterio.
Un punto de partida típico podría ser 350 °F y 30 minutos, al ser unos ajustes que suelen funcionar. Tras cada intento, se hacen ajustes en función del resultado.
Búsqueda aleatoria
Este enfoque consiste en seleccionar al azar combinaciones de temperatura y tiempo dentro de un rango. Por ejemplo, temperaturas entre 325 °F y 375 °F y tiempos entre 25 y 35 minutos.
La selección podría empezar con 330 °F durante 27 minutos, seguida de 370 °F durante 31 minutos, y así de forma aleatoria hasta identificar la combinación más eficaz.
Búsqueda en rejilla
Este método explora de forma sistemática múltiples combinaciones de valores de hiperparámetros.
Siguiendo con el ejemplo del horneado, la pastelera crea en la pared una rejilla estructurada con combinaciones de temperatura y tiempo.
La rejilla podría incluir incrementos de 5 °F entre 325 °F y 375 °F y de 2 minutos entre 25 y 35 minutos. Se hornea el bizcocho en cada combinación de la rejilla (325 °F durante 25 minutos, 325 °F durante 27 minutos, ... , 375 °F durante 35 minutos) para encontrar la mejor.
Búsqueda bayesiana
La optimización bayesiana puede entenderse como un enfoque más inteligente para encontrar la mejor temperatura y tiempo de horneado de un bizcocho frente a la búsqueda aleatoria.
La búsqueda aleatoria implicaría probar un amplio abanico de combinaciones al azar, muchas de las cuales darían como resultado bizcochos poco hechos o pasados.
En la optimización bayesiana, la búsqueda de las condiciones óptimas se guía e informa por los resultados anteriores.
Por ejemplo, si se observa que los bizcochos horneados en torno a 350 °F durante 30 minutos suelen salir mejor, a partir de ahí se concentrarán más pruebas en combinaciones de temperatura y tiempo cercanas a esos valores.
Este método reduce el número de intentos necesarios porque "aprende" qué combinaciones tienen más probabilidades de dar con el bizcocho perfecto según los resultados previos.
En resumen, la optimización bayesiana se basa en el teorema de Bayes para optimizar funciones objetivo costosas de evaluar. Es especialmente eficaz cuando muestrear es caro y la función objetivo es desconocida pero se puede muestrear.
Suele emplear un modelo probabilístico, como un proceso gaussiano, para estimar la función objetivo y una función de adquisición para decidir dónde muestrear a continuación.
Retos de la optimización bayesiana
Este método se ha aplicado con éxito en múltiples ámbitos. Aun así, presenta algunos desafíos importantes, entre ellos:
Evaluación por lotes/en paralelo
Un reto es realizar evaluaciones por lotes o en paralelo de forma eficiente. La optimización bayesiana tradicionalmente opera de manera secuencial, eligiendo un punto a la vez. Extenderla a escenarios por lotes, donde se evalúan varios puntos simultáneamente, no es trivial y requiere un equilibrio cuidadoso para asegurar diversidad y eficiencia en los puntos elegidos.
Optimización no miope
Se refiere a tomar decisiones estratégicas a largo plazo sobre qué puntos evaluar. Los métodos no miopes consideran el impacto futuro de las evaluaciones actuales, lo que puede ser costoso computacionalmente y complejo de modelar.
Dimensionalidad del espacio
A medida que aumenta la dimensionalidad del espacio de búsqueda, la optimización bayesiana puede perder eficacia. Esto se debe a la "maldición de la dimensionalidad", por la que el volumen del espacio crece exponencialmente y resulta más difícil encontrar óptimos con un número limitado de evaluaciones.
Espacios de búsqueda estructurados
En muchos problemas reales, el espacio de búsqueda no es un espacio n-dimensional continuo y simple, sino que tiene estructuras complejas, como dependencias entre variables o restricciones. Tratar estos espacios de forma eficaz es todo un desafío.
Búsqueda multiobjetivo/multitarea y multifidelidad
Ampliar la optimización bayesiana para manejar varios objetivos a la vez o integrar información de evaluaciones con distinta fidelidad (precisión) es complejo. Estos escenarios exigen equilibrar tanto objetivos como niveles de detalle en las evaluaciones.
Arranque en caliente (warm start)
Consiste en aprovechar conocimiento o datos previos para acelerar el proceso de optimización. Incorporar esta información en el marco bayesiano sin sesgar los resultados es complicado.
Gran número de evaluaciones
Aunque la optimización bayesiana está pensada para escenarios donde evaluar es caro, en algunos casos aún puede requerirse un gran número de evaluaciones. Gestionarlas y navegar por ellas de forma eficiente puede ser difícil, tanto por recursos computacionales como por tiempo.
Funciones objetivo "difíciles"
Lidiar con funciones objetivo con muchos óptimos locales, discontinuidades o no estacionariedad (cuando la función cambia en el tiempo) es complicado. Estas funciones pueden desorientar el proceso de optimización y dificultar encontrar el óptimo global.
Observación indirecta
En algunos casos, la función objetivo no puede observarse directamente, solo a través de medidas indirectas. Esto añade complejidad, ya que el algoritmo debe inferir la función objetivo real a partir de observaciones indirectas.
Funciones de adquisición y toma de decisiones
En optimización bayesiana, las funciones de adquisición guían la búsqueda de los valores óptimos.
Las funciones de adquisición y los modelos sustitutos (surrogate) son interdependientes en la optimización bayesiana.
El modelo sustituto ofrece una predicción probabilística de la función objetivo, que la función de adquisición utiliza para decidir qué puntos conviene evaluar a continuación. Además, modelos como la regresión con procesos gaussianos son especialmente útiles cuando la función objetivo es compleja o costosa de evaluar directamente.
Actualizando continuamente el modelo sustituto con nuevos datos, la función de adquisición puede dirigirse con mayor precisión a las zonas del espacio de búsqueda con más posibilidades de ofrecer los mejores resultados.
Entre las funciones de adquisición más usadas se encuentran:
- Thompson Sampling: selecciona puntos basándose en una estimación probabilística de la función objetivo.
- Upper Confidence Bound (UCB): elige el punto con mayor probabilidad de mejorar el mejor valor observado. Utiliza la diferencia entre el posible resultado de la nueva solución y el mejor actual, calculando la probabilidad de mejora.
- Probability of Improvement (PI): elige el punto con mayor probabilidad de superar el mejor valor observado hasta el momento.
- Expected Improvement (EI): selecciona el punto con mayor mejora esperada respecto al mejor valor observado.
No hay una función universalmente mejor o peor. Cada una tiene sus fortalezas y se elige según las necesidades concretas del problema de optimización.
Aplicaciones de la optimización bayesiana
La optimización bayesiana se ha aplicado con éxito en muchos sectores. Aquí la ilustramos con cuatro casos de uso:
- Procesamiento del lenguaje natural
- Aprendizaje automático y ajuste de hiperparámetros
- Pruebas A/B, y
- Aprendizaje por refuerzo y robótica
Son ejemplos especialmente relevantes e informativos para Data Scientists.
Procesamiento del lenguaje natural
Al aplicar aprendizaje automático a problemas de procesamiento del lenguaje natural, hay múltiples decisiones sobre cómo representar los textos de entrada, y estas elecciones influyen en el resultado del modelo.
La optimización bayesiana se usa para automatizar la elección de la mejor representación del texto en modelos de PLN, simplificando y agilizando el desarrollo sin perder rendimiento, e incluso mejorándolo.
Si quieres saber más sobre embeddings, nuestro curso Introduction to Embeddings with OpenAI API ofrece una guía completa para crear embeddings con la API de OpenAI.
Aprendizaje automático y ajuste de hiperparámetros
En AutoML, la optimización bayesiana automatiza la selección del mejor modelo y sus hiperparámetros para un problema y conjunto de datos concretos.
Aplicaciones recientes han demostrado su eficacia ajustando modelos complejos como deep belief networks, redes neuronales convolucionales y métodos de Monte Carlo con cadenas de Markov.
Además, ha sido útil para automatizar la selección entre modelos de librerías populares como WEKA y scikit-learn.
Pruebas A/B
En pruebas A/B, la optimización bayesiana mejora la eficiencia al testar distintas configuraciones de producto, como anuncios, apps, juegos o sitios web.
Mostrando dos opciones (A y B) a un subconjunto pequeño de usuarios, los equipos recogen feedback para optimizar métricas como la interacción o el CTR. El reto clave es identificar la mejor configuración con un presupuesto limitado de consultas a usuarios.
La optimización bayesiana facilita el proceso usando el feedback de pruebas anteriores para decidir a qué subconjuntos consultar después, con el objetivo de optimizar el rendimiento general minimizando costes de oportunidad.
Aprendizaje por refuerzo y robótica
La optimización bayesiana se ha aplicado con eficacia tanto en robótica como en aprendizaje por refuerzo.
En robótica, se ha utilizado para optimizar la marcha de un robot según objetivos como velocidad o suavidad, como se demostró con el Sony AIBO ERS-7. También se ha empleado en tareas de navegación, ayudando a los robots a reducir la incertidumbre sobre su localización y los mapas mientras se mueven por entornos.
En aprendizaje por refuerzo jerárquico, se ha aplicado para ajustar automáticamente parámetros de políticas de redes neuronales y aprender funciones de valor a distintos niveles de un sistema jerárquico.
Además, se ha utilizado para desarrollar políticas de atención en seguimiento de imágenes con redes profundas, lo que demuestra su versatilidad para adaptarse a diferentes aspectos del aprendizaje y la toma de decisiones en entornos complejos.
Guía paso a paso para implementar optimización bayesiana
En las secciones anteriores has visto una visión completa de la optimización bayesiana. Ahora veremos cómo optimizar los hiperparámetros de un XGBRegressor con la librería GPyOpt.
PyMC3 es otra librería potente para optimización bayesiana, y nuestro curso Bayesian Data Analysis in Python ofrece una guía completa con ejemplos reales.
Si te interesa aplicar optimización bayesiana en R, nuestro curso Fundamentals of Bayesian Data Analysis in R es para ti.
Aplicaremos dos métodos: búsqueda en rejilla y optimización bayesiana. El objetivo es ver cuál proporciona los mejores hiperparámetros y, por tanto, un mejor modelo. El código completo está disponible en este cuaderno de DataLab; puedes crear tu propia copia para editar y ejecutar el código en el navegador sin instalar nada en tu ordenador.
Requisitos previos
Necesitarás las siguientes librerías para ejecutar ambas técnicas con éxito.
- numpy: librería para computación numérica en Python.
- scipy: librería para computación científica en Python.
- sklearn: librería de aprendizaje automático en Python.
- GPyOpt: librería para optimización bayesiana en Python.
- Xgboost para el modelo XGBoost
Estas librerías pueden instalarse con pip desde Jupyter Notebook así:
!pip -q install xgboost scikit-learn GPyOpt numpy
Tras ejecutar el comando anterior, importamos los módulos con la sentencia import:
import xgboost as xgb
from sklearn.datasets import fetch_california_housing as fch
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import RandomizedSearchCV
from GPyOpt.methods import BayesianOptimization
from sklearn.model_selection import cross_val_score
import numpy as np
Preparación del dataset
El análisis comparativo se basa en el conjunto de datos de vivienda de California.
- El 70% de los datos se usa para entrenar el modelo XGBoost
- El 30% restante se usa para pruebas
La partición de entrenamiento y prueba se realiza así:
# Load dataset
california_housing = fch()
X = california_housing.data
y = california_housing.target
# Split the dataset into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y,
test_size=0.3,
random_state=2024)
Tras cargar los datos de entrenamiento y prueba, podemos comprobar sus tamaños con .shape.
print(f"Training Shape: {X_train.shape}")
print(f"Testing Shape: {X_test.shape}")
Ajuste de hiperparámetros con búsqueda aleatoria
Esta sección explica cómo configurar y ejecutar el ajuste de hiperparámetros con el enfoque de búsqueda en rejilla para una regresión XGBoost usando la clase RandomizedSearchCV del módulo scikit-learn.
Configurar la rejilla de parámetros
Se crea un diccionario llamado param_dist con distintos hiperparámetros como claves y listas de valores posibles como valores. Entre ellos:
- max_depth: profundidad máxima de un árbol. Valores: 3, 10, 5, 15.
- min_child_weight: suma mínima de pesos (hessiano) necesaria en un nodo hijo. Valores: 1, 5, 10.
- subsample: proporción de muestreo de las instancias de entrenamiento. Valores: 0.5, 0.7, 1.0.
- colsample_bytree: proporción de columnas al construir cada árbol. Valores: 0.5, 0.7, 1.0.
- n_estimators: número de árboles potenciados por gradiente (rondas de boosting). Valores: 100, 200, 300, 400.
param_dist = {
'max_depth': [3, 10, 5, 15],
'min_child_weight': [1, 5, 10],
'subsample': [0.5, 0.7, 1.0],
'colsample_bytree': [0.5, 0.7, 1.0],
'n_estimators': [100, 200, 300, 400],
'learning_rate': [0.01, 0.05, 0.1, 0.15, 0.2]
}
Inicializar el regresor XGBoost
Se crea una instancia de la clase XGBRegressor de la librería XGBoost:
xgb_reg = xgb.XGBRegressor()
Configurar RandomizedSearchCV
RandomizedSearchCV se configura con estos parámetros:
- El estimador (xgb_reg) es el regresor XGBoost.
- param_distributions=param_dist especifica el diccionario de parámetros a muestrear.
- n_iter=25 indica que se probarán 25 combinaciones.
- scoring='neg_mean_squared_error' fija la métrica al error cuadrático medio negativo.
- cv=3 establece validación cruzada de 3 particiones.
- verbose=1 activa salida detallada.
- random_state=42 garantiza reproducibilidad.
random_search = RandomizedSearchCV(
xgb_reg, param_distributions=param_dist, n_iter=25,
scoring='neg_mean_squared_error', cv=3, verbose=1, random_state=2024
)
Entrenar el modelo y consultar parámetros
El método fit se usa para ejecutar la búsqueda aleatoria sobre los datos de entrenamiento (X_train e y_train):
random_search.fit(X_train, y_train)
El atributo best_params del modelo entrenado contiene los mejores hiperparámetros que han dado mejor rendimiento.
Puedes obtenerlos así:
print("Random Search Best Parameters:", random_search.best_params_)

Mejores parámetros con búsqueda aleatoria
De entre todos los parámetros posibles, los mejores para el modelo XGBoost con búsqueda aleatoria son:
'subsample': 0.5,
'n_estimators': 400,
'min_child_weight': 5,
'max_depth': 10,
'learning_rate': 0.05,
'colsample_bytree': 1.0
}
Evaluar el modelo
Con estos valores, evaluamos el modelo y obtenemos su rendimiento así:
Primero, inicializamos el modelo con los mejores hiperparámetros y lo entrenamos.
# Initialize and train the model
model_random_search = xgb.XGBRegressor(**params_random_search)
model_random_search.fit(X_train, y_train)
Después, evaluamos el modelo con los datos de prueba:
predictions_random_search = model_random_search.predict(X_test)
mse_random_search = mean_squared_error(y_test, predictions_random_search)
print("MSE for Random Search: ", mse_random_search)
La ejecución correcta de los bloques anteriores genera el siguiente valor de error cuadrático medio:

MSE para XGBoost usando hiperparámetros de búsqueda aleatoria
Ajuste de hiperparámetros con optimización bayesiana
De forma similar a la búsqueda aleatoria, seguimos un proceso paso a paso para obtener los mejores hiperparámetros con optimización bayesiana.
Definir los rangos de los parámetros
Los límites de los hiperparámetros se definen en la lista baysian_opt_bounds. Cada hiperparámetro se representa como un diccionario con las claves: name, type y domain.
- max_depth, min_child_weight, n_estimators son variables discretas.
- subsample, colsample_bytree, learning_rate son variables continuas.
- El domain especifica el rango de valores para cada hiperparámetro.
baysian_opt_bounds = [
{'name': 'max_depth', 'type': 'discrete', 'domain': (3, 10, 5, 15)},
{'name': 'min_child_weight', 'type': 'discrete', 'domain': (1, 5, 10)},
{'name': 'subsample', 'type': 'continuous', 'domain': (0.5, 1.0)},
{'name': 'colsample_bytree', 'type': 'continuous', 'domain': (0.5, 1.0)},
{'name': 'n_estimators', 'type': 'discrete', 'domain': (100, 200, 300, 400)},
{'name': 'learning_rate', 'type': 'continuous', 'domain': (0.01, 0.2)}
]
Definir la función objetivo
Se define una función objetivo xgb_cv_score para calcular el error cuadrático medio negativo con validación cruzada de un modelo XGBoost.
- La función recibe un conjunto de parámetros y los convierte al formato requerido.
- cross_val_score evalúa el modelo XGBoost con los parámetros indicados.
- Se devuelve la media negativa de las puntuaciones de la validación cruzada como objetivo a minimizar.
def xgb_cv_score(parameters):
parameters = parameters[0]
score = -cross_val_score(
xgb.XGBRegressor(
max_depth=int(parameters[0]),
min_child_weight=int(parameters[1]),
subsample=parameters[2],
colsample_bytree=parameters[3],
n_estimators=int(parameters[4]),
learning_rate=parameters[5]),
X_train, y_train, scoring='neg_mean_squared_error', cv=3).mean()
return score
Inicializar y ejecutar el modelo bayesiano
Instanciamos la optimización bayesiana con estos parámetros:
- f=xgb_cv_score: la función objetivo a minimizar.
- domain=baysian_opt_bounds: los rangos de hiperparámetros.
- model_type='GP': usa procesos gaussianos.
- acquisition_type='EI': usa Expected Improvement como función de adquisición.
- max_iter=25: número de iteraciones del proceso.
El proceso de optimización se inicia con optimizer.run_optimization()
optimizer = BayesianOptimization(
f=xgb_cv_score, domain=baysian_opt_bounds, model_type='GP',
acquisition_type='EI', max_iter=25
)
optimizer.run_optimization()
Obtener los mejores parámetros
Tras la optimización, se extraen y formatean los mejores parámetros:
- Se recuperan desde optimizer.x_opt.
- Los parámetros discretos (max_depth, min_child_weight, n_estimators) se convierten a enteros.
Se imprimen los mejores parámetros:
print("Bayesian Optimization Best Parameters:", best_params_bayesian)

Mejores parámetros con optimización bayesiana
Evaluar el modelo
La inicialización y el entrenamiento son iguales que antes, pero ahora usamos los parámetros de la optimización bayesiana:
params_bayesian_opt = {
'max_depth': 10,
'min_child_weight': 10,
'subsample': 0.820222997732141,
'colsample_bytree': 0.6710357796023916,
'n_estimators': 300,
'learning_rate': 0.04797554348030097
}
# Initialize and train the model
model_bayesian_opt = xgb.XGBRegressor(**params_bayesian_opt)
model_bayesian_opt.fit(X_train, y_train)
# Make predictions and evaluate
predictions_bayesian_opt = model_bayesian_opt.predict(X_test)
mse_bayesian_opt = mean_squared_error(y_test, predictions_bayesian_opt)
print("MSE for Bayesian Optimization: ", mse_bayesian_opt)
Tras ejecutar el código anterior, se muestra el rendimiento del modelo. El resultado es el siguiente:

MSE para XGBoost usando hiperparámetros de optimización bayesiana
Interpretación de resultados
De los dos experimentos se observa que:
- Menor MSE con optimización bayesiana: el modelo entrenado con hiperparámetros de optimización bayesiana tiene un MSE menor (0.204) que el de búsqueda aleatoria (0.219). Este valor más bajo sugiere que, de media, el modelo se aproxima más a los valores reales.
- Rendimiento del modelo: el MSE inferior indica que la optimización bayesiana fue más eficaz ajustando los hiperparámetros para el modelo XGBoost. Sugiere que el modelo ajustado con este método generaliza mejor de los datos de entrenamiento a los no vistos (el conjunto de prueba).
- Eficiencia de la optimización bayesiana: suele ofrecer mejor rendimiento en el ajuste de hiperparámetros porque usa un modelo probabilístico para guiar la búsqueda. Aprende de evaluaciones previas y dirige la exploración hacia las zonas más prometedoras, lo que a menudo conduce a mejores valores que la búsqueda aleatoria.
En este caso concreto, la optimización bayesiana proporcionó mejores resultados, como muestra el MSE más bajo. Para este dataset y modelo (XGBoost), fue más efectiva identificando el conjunto de hiperparámetros que minimiza el error de predicción en el conjunto de prueba.
Ten en cuenta que, aunque aquí la optimización bayesiana rinde mejor, la elección entre búsqueda aleatoria y optimización bayesiana puede depender de factores como la complejidad del modelo, la naturaleza de los datos y los recursos computacionales.
No obstante, en escenarios donde la precisión del ajuste de hiperparámetros es clave y cuentas con recursos, la optimización bayesiana suele ser la opción superior.
Conclusión
Este artículo ha ofrecido una exploración detallada de la optimización bayesiana, una técnica clave para optimizar funciones complejas.
Empezamos definiendo qué es la optimización bayesiana y repasando los retos de la optimización de funciones, que justifican su relevancia.
Mediante una guía práctica, profundizamos en su implementación, centrándonos en procesos gaussianos y funciones de adquisición. Una parte importante del contenido se dedicó a aplicar optimización bayesiana al ajuste de hiperparámetros en modelos de aprendizaje automático, demostrando su utilidad real.
En conjunto, este artículo sirve como introducción y guía práctica, destacando el papel fundamental de la optimización bayesiana en el aprendizaje automático y la optimización computacional.
Aporta ideas valiosas para profesionales, investigadores y entusiastas, subrayando su aplicabilidad e impacto en los desafíos computacionales modernos.
Si quieres profundizar en optimización bayesiana y su implementación en Python, nuestro curso Hyperparameter Tuning in Python te ofrece experiencia práctica con metodologías habituales de ajuste automatizado de hiperparámetros usando la librería Scikit Learn. Entre las avanzadas se incluyen algoritmos bayesianos y genéticos.
Zoumana desarrolla herramientas de IA LLM para ayudar a las empresas a llevar a cabo la diligencia debida en materia de sostenibilidad y evaluaciones de riesgos. Anteriormente trabajó como científico de datos e ingeniero de aprendizaje automático en Axionable e IBM. Zoumana es la fundadora de la plataforma tecnológica educativa de aprendizaje entre iguales ETP4Africa. Ha escrito más de 20 tutoriales para DataCamp.


