en Ciencia de datosno es raro encontrar problemas con objetivos competitivos. Ya sea diseñando productos, algoritmos de ajuste u optimización de carteras, a menudo necesitamos equilibrar varias métricas para obtener el mejor resultado posible. A veces, maximizar una métrica se produce a expensas de otra, lo que hace que sea difícil tener una solución optimizada general.
Mientras que existen varias soluciones para resolver múltiples objetivos Mejoramiento Problemas, encontré que la función de deseabilidad es elegante y fácil de explicar a la audiencia no técnica. Lo que los convierte en una opción interesante para considerar. Las funciones de deseos combinarán varias métricas en una puntuación estandarizada, lo que permite una optimización holística.
En este artículo, exploraremos:
- La base matemática de las funciones de deseabilidad
- Cómo implementar estas funciones en Pitón
- Cómo optimizar un problema de múltiples objetivos con funciones de deseabilidad
- Visualización para la interpretación y explicación de los resultados
Para fundamentar estos conceptos en un ejemplo real, aplicaremos funciones de deseabilidad para optimizar una cocción de pan: un problema de juguete con algunos parámetros interconectados y objetivos de calidad en competencia que nos permitirán explorar varias opciones de optimización.
Al final de este artículo, tendrá una nueva herramienta poderosa en su kit de herramientas de ciencia de datos para abordar los problemas de optimización de objetivos múltiples en numerosos dominios, así como un código completamente funcional disponible aquí en Github.
¿Cuáles son las funciones de deseabilidad?
Las funciones de deseabilidad se formalizaron primero por Harrington (1965) y luego extendido por Derringer y Suich (1980). La idea es:
- Transforme cada respuesta en una puntuación de rendimiento entre 0 (absolutamente inaceptable) y 1 (el valor ideal)
- Combine todos los puntajes en una sola métrica para maximizar
Exploremos los tipos de funciones de deseabilidad y luego cómo podemos combinar todos los puntajes.
Los diferentes tipos de funciones de deseabilidad
Hay tres funciones de deseabilidad diferentes que permitirían manejar muchas situaciones.
- Más pequeño: Se usa al minimizar una respuesta
def desirability_smaller_is_better(x: float, x_min: float, x_max: float) -> float:
"""Calculate desirability function value where smaller values are better.
Args:
x: Input parameter value
x_min: Minimum acceptable value
x_max: Maximum acceptable value
Returns:
Desirability score between 0 and 1
"""
if x <= x_min:
return 1.0
elif x >= x_max:
return 0.0
else:
return (x_max - x) / (x_max - x_min)
- Más grande: Se usa al maximizar una respuesta
def desirability_larger_is_better(x: float, x_min: float, x_max: float) -> float:
"""Calculate desirability function value where larger values are better.
Args:
x: Input parameter value
x_min: Minimum acceptable value
x_max: Maximum acceptable value
Returns:
Desirability score between 0 and 1
"""
if x <= x_min:
return 0.0
elif x >= x_max:
return 1.0
else:
return (x - x_min) / (x_max - x_min)
- Objetivo es el mejor: Utilizado cuando un valor objetivo específico es óptimo
def desirability_target_is_best(x: float, x_min: float, x_target: float, x_max: float) -> float:
"""Calculate two-sided desirability function value with target value.
Args:
x: Input parameter value
x_min: Minimum acceptable value
x_target: Target (optimal) value
x_max: Maximum acceptable value
Returns:
Desirability score between 0 and 1
"""
if x_min <= x <= x_target:
return (x - x_min) / (x_target - x_min)
elif x_target < x <= x_max:
return (x_max - x) / (x_max - x_target)
else:
return 0.0
Cada parámetro de entrada se puede parametrizar con una de estas tres funciones de deseabilidad, antes de combinarlas en una sola puntuación de deseabilidad.
Combinando puntajes de deseabilidad
Una vez que las métricas individuales se transforman en puntajes de deseabilidad, deben combinarse en una deseabilidad general. El enfoque más común es la media geométrica:
Donde di son valores individuales de deseabilidad y wi son pesos que reflejan la importancia relativa de cada métrica.
La media geométrica tiene una propiedad importante: si alguna deseabilidad única es 0 (es decir, completamente inaceptable), la deseabilidad general también es 0, independientemente de otros valores. Esto aplica que todos los requisitos deben cumplirse hasta cierto punto.
def overall_desirability(desirabilities, weights=None):
"""Compute overall desirability using geometric mean
Parameters:
-----------
desirabilities : list
Individual desirability scores
weights : list
Weights for each desirability
Returns:
--------
float
Overall desirability score
"""
if weights is None:
weights = [1] * len(desirabilities)
# Convert to numpy arrays
d = np.array(desirabilities)
w = np.array(weights)
# Calculate geometric mean
return np.prod(d ** w) ** (1 / np.sum(w))
Los pesos son hiperparámetros que dan apalancamiento sobre el resultado final y dan espacio para la personalización.
Un ejemplo de optimización práctica: hornear pan
Para demostrar funciones de deseabilidad en la acción, apliquemos a un problema de juguete: un problema de optimización de pan para hornear.
Los parámetros y las métricas de calidad
Juguemos con los siguientes parámetros:
- Tiempo de fermentación (30-180 minutos)
- Temperatura de fermentación (20–30 ° C)
- Nivel de hidratación (60–85%)
- Tiempo de amasado (0–20 minutos)
- Temperatura de hornear (180–250 ° C)
Y tratemos de optimizar estas métricas:
- Calidad de textura: La textura del pan
- Perfil de sabor: El sabor del pan
- Sentido práctico: La practicidad de todo el proceso
Por supuesto, cada una de estas métricas depende de más de un parámetro. Así que aquí viene uno de los pasos más críticos: los parámetros de mapeo de las métricas de calidad.
Para cada métrica de calidad, necesitamos definir cómo los parámetros lo influyen:
def compute_flavor_profile(params: List[float]) -> float:
"""Compute flavor profile score based on input parameters.
Args:
params: List of parameter values [fermentation_time, ferment_temp, hydration,
kneading_time, baking_temp]
Returns:
Weighted flavor profile score between 0 and 1
"""
# Flavor mainly affected by fermentation parameters
fermentation_d = desirability_larger_is_better(params[0], 30, 180)
ferment_temp_d = desirability_target_is_best(params[1], 20, 24, 28)
hydration_d = desirability_target_is_best(params[2], 65, 75, 85)
# Baking temperature has minimal effect on flavor
weights = [0.5, 0.3, 0.2]
return np.average([fermentation_d, ferment_temp_d, hydration_d],
weights=weights)
Aquí, por ejemplo, el sabor está influenciado por lo siguiente:
- El tiempo de fermentación, con una conveniencia mínima por debajo de los 30 minutos y una máxima deseabilidad superior a los 180 minutos
- La temperatura de fermentación, con una máxima deseabilidad de alcance a los 24 grados centígrados
- La hidratación, con una máxima deseabilidad, alcance el 75% de la humedad
Estos parámetros calculados se ponderan luego para devolver la deseabilidad del sabor. Cálculos similares y hechos para la calidad y practicidad de la textura.
La función objetivo
Siguiendo el enfoque de la función de deseabilidad, utilizaremos la deseabilidad general como nuestra función objetivo. El objetivo es maximizar esta puntuación general, lo que significa encontrar parámetros que mejor satisfagan nuestros tres requisitos simultáneamente:
def objective_function(params: List[float], weights: List[float]) -> float:
"""Compute overall desirability score based on individual quality metrics.
Args:
params: List of parameter values
weights: Weights for texture, flavor and practicality scores
Returns:
Negative overall desirability score (for minimization)
"""
# Compute individual desirability scores
texture = compute_texture_quality(params)
flavor = compute_flavor_profile(params)
practicality = compute_practicality(params)
# Ensure weights sum up to one
weights = np.array(weights) / np.sum(weights)
# Calculate overall desirability using geometric mean
overall_d = overall_desirability([texture, flavor, practicality], weights)
# Return negative value since we want to maximize desirability
# but optimization functions typically minimize
return -overall_d
Después de calcular las deseos individuales para la textura, el sabor y la practicidad; La deseabilidad general simplemente se calcula con una media geométrica ponderada. Finalmente devuelve la deseabilidad general negativa, para que pueda minimizarse.
Optimización con Scipy
Finalmente usamos Bisagro‘s minimize función para encontrar parámetros óptimos. Dado que devolvimos la deseabilidad general negativa como la función objetivo, minimizarla maximizaría la deseabilidad general:
def optimize(weights: list[float]) -> list[float]:
# Define parameter bounds
bounds = {
'fermentation_time': (1, 24),
'fermentation_temp': (20, 30),
'hydration_level': (60, 85),
'kneading_time': (0, 20),
'baking_temp': (180, 250)
}
# Initial guess (middle of bounds)
x0 = [(b[0] + b[1]) / 2 for b in bounds.values()]
# Run optimization
result = minimize(
objective_function,
x0,
args=(weights,),
bounds=list(bounds.values()),
method='SLSQP'
)
return result.x
En esta función, después de definir los límites para cada parámetro, la suposición inicial se calcula como la mitad de los límites, y luego se da como entrada al minimize función de scipy. El resultado finalmente se devuelve.
Los pesos también se dan como entrada al optimizador y son una buena manera de personalizar la salida. Por ejemplo, con un mayor peso en la practicidad, la solución optimizada se centrará en la practicidad sobre el sabor y la textura.
Ahora visualicemos los resultados para algunos conjuntos de pesos.
Visualización de resultados
Veamos cómo el optimizador maneja diferentes perfiles de preferencia, demostrando la flexibilidad de las funciones de deseabilidad, dados varios pesos de entrada.
Echemos un vistazo a los resultados en caso de pesas que favorecen la practicidad:
Con pesos en gran medida a favor de la practicidad, la deseabilidad general lograda es de 0.69, con un corto tiempo de amasado de 5 minutos, ya que un valor alto impacta negativamente la practicidad.
Ahora, si optimizamos con énfasis en la textura, tenemos resultados ligeramente diferentes:
En este caso, la deseabilidad general lograda es 0.85, significativamente mayor. El tiempo de amasado es esta vez 12 minutos, ya que un valor más alto impacta positivamente la textura y no se penaliza tanto por la practicidad.
Conclusión: Aplicaciones prácticas de funciones de deseabilidad
Si bien nos centramos en la cocción del pan como nuestro ejemplo, el mismo enfoque se puede aplicar a varios dominios, como la formulación del producto en cosméticos o asignación de recursos en la optimización de la cartera.
Las funciones de deseabilidad proporcionan un poderoso marco matemático para abordar problemas de optimización de objetivos múltiples en numerosas aplicaciones de ciencia de datos. Al transformar las métricas sin procesar en puntajes de deseabilidad estandarizados, podemos combinar y optimizar de manera efectiva los objetivos dispares.
Las ventajas clave de este enfoque incluyen:
- Escalas estandarizadas que hacen que diferentes métricas sean comparables y fáciles de combinar en un solo objetivo
- Flexibilidad para manejar diferentes tipos de objetivos: minimizar, maximizar, objetivo
- Comunicación clara de preferencias a través de funciones matemáticas
El código presentado aquí proporciona un punto de partida para su propia experimentación. Ya sea que esté optimizando los procesos industriales, los modelos de aprendizaje automático o las formulaciones de productos, con suerte, las funciones de deseabilidad ofrecen un enfoque sistemático para encontrar el mejor compromiso entre los objetivos competitivos.