Optimización de inventario con Ciencia de Datos Tutorial práctico con Python

Optimización de inventario con Ciencia de Datos Tutorial práctico con Python' can be condensed to 'Optimización de inventario con Ciencia de Datos y Python

Parte 1: Una Introducción Amigable a la Implementación del Proceso de Markov para la Optimización de Inventario.

Foto de Christin Hume en Unsplash

Introducción

La optimización de inventario es como resolver un rompecabezas complicado. Como un problema amplio, surge en muchos dominios, se trata de averiguar cuántos productos ordenar para tu tienda.

Imagina a un dueño de una tienda de bicicletas que ordena nuevas bicicletas para la venta. Pero aquí hay una situación complicada. Si ordena demasiadas bicicletas para la tienda, gastará demasiado en mantener y almacenar las bicicletas. Por otro lado, si ordena menos bicicletas, es posible que no tenga suficientes bicicletas para satisfacer las demandas de los clientes, lo que significa pérdida de ganancias y (reputación).

Lo que ella necesita es una “estrategia” óptima que la ayude a tomar la mejor decisión diaria sobre cuánto ordenar, asegurando ganancias a largo plazo para su inventario.

Entonces, en el contexto de este problema, los científicos de datos con conocimientos en programación, datos y modelado pueden desempeñar un papel importante en averiguar esta mejor “estrategia”. Sin embargo, necesitamos algunos conocimientos fundamentales para alcanzar ese objetivo (para responder esa pregunta). Necesitamos tener una comprensión básica sobre:

  • Proceso de Markov,
  • Proceso de Recompensas de Markov
  • y Procesos de Decisión de Markov.
  • Finalmente, combinaremos estos tres conceptos y los conectaremos con
  • Programación Dinámica y
  • Aprendizaje por Reforzamiento

Para llegar a la “estrategia” óptima que mencioné antes. Este blog tiene como objetivo comprender y modelar “Procesos de Markov” en Python, que serán un bloque de construcción para los próximos pasos.

Optimización de Inventario: ¿Pueden los Modelos de Aprendizaje Automático Listos para Usar Resolverlo?

Honestamente, escribí este blog “por frustración” para ver cómo se modela y resuelve la optimización de inventario en los recursos en línea. En mi doctorado, tuve que lidiar con la optimización de inventario (ya que mi tema es Toma de Decisiones Secuenciales). Investigué y revisé artículos y algunos libros y pude encontrar el enfoque de modelado correcto sobre cómo resolverlo “consistentemente”.

El punto es que los problemas de tipo “Optimización de Inventario” son problemas dinámicos, donde dada la situación (situación de inventario) en la que te encuentras, necesitas adaptarte a esa situación y tener una política adaptativa.

La optimización de inventario no es un problema estático que se puede abordar con un método analítico estático, ni se puede resolver utilizando modelos de aprendizaje automático / aprendizaje profundo listos para usar. Es un proceso dinámico donde sus componentes deben ser comprendidos y modelados, lo que te permite adaptar dinámicamente las decisiones diarias.

Proceso de Markov

Si eres un profesional analítico (ya sea un científico de datos, analista, etc.), a menudo tratarás con Procesos que están indexados en el tiempo y siguen un camino incierto. Piensa en un científico de datos que trabaja en una compañía de energía. Su tarea implica llevar un registro del camino incierto de los precios de las materias primas.

El precio de la materia prima (petróleo, por ejemplo) seguirá un camino en pasos de tiempo t=0,1,2,⋯. Este es un proceso incierto donde se indexa por tiempo. Sin embargo, si queremos hacer un análisis, necesitamos representar internamente el proceso.

Estado

Considera el Estado como una herramienta para representar internamente el proceso incierto. Volvamos al ejemplo de los precios del petróleo. Digamos que el precio del petróleo hoy es de 100$. Puedo representar esa información diciendo S_0=100, luego mañana el precio será diferente, se puede representar como S_1, y esta secuencia continúa S_0, S_1, S_2. El proceso es una secuencia de estados aleatorios St∈S, a medida que el tiempo t=0,1,2,3,.. — Podemos representar el proceso con:

Propiedad de Markov

Aquí, en este breve blog, quiero hablar sobre el Proceso de Markov. Llamamos al proceso (Markoviano) si tiene una Propiedad de Markov, lo que significa que la transición de estados tiene la siguiente (propiedad):

¿Qué significa esta ecuación en términos más simples?

Podemos pensar en un ejemplo simple del clima. Supongamos que un día puede tener tres posibles condiciones climáticas, “Soleado”, “Lluvioso” y “Nevado”. Entonces, si hoy es “Soleado”,

  • Hay un 70% de probabilidad de que mañana también esté “Soleado”,
  • Un 20% de probabilidad de que el clima cambie a “Lluvioso” mañana, y
  • Un 10% de probabilidad de que el clima de mañana sea “Nevado”.

En este ejemplo del clima, podemos ver que la probabilidad de la condición climática de mañana, “solamente” depende de “hoy”, por lo que la historia de la condición climática es “irrelevante”. Mientras el clima hoy sea soleado (St=”Soleado”), la probabilidad de que el clima de mañana sea P(S_{t+1}=”Soleado”)=0.7, P(S_{t+1}=”Lluvioso”)=0.2 y P(S_{t+1}=”Nevado”)=0.1.

Trabajemos en un ejemplo simple del mundo real para comprender mejor el Proceso de Markov. Aquí, el ejemplo trata sobre la gestión del inventario de una tienda de bicicletas y se seguirá con una programación práctica en Python.

Un Ejemplo Simple de Gestión del Inventario de una Tienda de Bicicletas

Foto de Christin Hume en Unsplash

Volviendo al ejemplo de la tienda de bicicletas: Imagina que tienes una tienda de bicicletas con un inventario que solo puede contener cierta cantidad de bicicletas (capacidad limitada). Por ejemplo, supongamos que tu tienda puede tener un máximo de 5 bicicletas.

Cada día, algunos clientes vienen a comprar bicicletas en tu tienda. Supongamos que hoy (miércoles), tienes tres bicicletas en tu tienda. Sin embargo, también sabes que mañana (jueves), habrá cierta demanda para tu tienda, lo que significa que algunas de tus bicicletas se venderán. No estás seguro de cuántos clientes tendrás mañana, es decir, la demanda exacta de bicicletas para mañana es incierta. Necesitamos modelar este proceso de manera más precisa, modelar cómo cambia y evoluciona el estado del inventario. ¹

Descripción del Problema

En este blog, nuestro enfoque principal está en el Proceso de Markov. Esto significa que en este blog, tendremos (asumimos) una política fija (en este caso, la política es cuántas bicicletas pedir cada día). Para modelar el Proceso de Markov de este ejemplo, primero necesitamos definir este problema (¿cuál es el estado?). En segundo lugar, necesitamos construir el modelo de transición de estados.

El estado (la representación interna del proceso) se puede describir mediante dos componentes:

  • α: es el número de bicicletas que ya tienes en la tienda
  • β: es el número de bicicletas que pediste el día anterior y que llegarán mañana por la mañana (estas bicicletas están en un camión)

Secuencia del ciclo de 24 horas

La secuencia de eventos en un ciclo de 24 horas para esta tienda de bicicletas es la siguiente:

  1. A las 6 PM: observas el estado S_t:(α,β)
  2. A las 6 PM: pides las bicicletas nuevas, igual a max(C−(α+β),0)
  3. A las 6 AM: recibes las bicicletas que pediste hace 36 horas
  4. A las 8 AM: abres la tienda
  5. De 8 AM a 6 PM experimentas la demanda i durante el día (modelada usando una distribución de Poisson) más abajo.
  6. A las 6 PM cierras la tienda

El diagrama a continuación visualiza esta secuencia:

La secuencia de eventos en un ciclo de 24 horas para la tienda de bicicletas — Fuente de la imagen: Autor

Siguiendo la explicación anterior, St=(αt+βt) es la representación interna de este proceso estocástico, y en el Proceso de Markov, queremos modelar cómo evoluciona este proceso estocástico.

Un ejemplo que demuestra una secuencia de 24 horas de inventario.

Permíteme dar un ejemplo. Digamos que David es el dueño de una tienda de bicicletas. Un miércoles (6 PM), tiene 2 bicicletas en su tienda y una bicicleta que ordenó el lunes a las 6 PM. Su estado sería:

Entonces, el estado en el momento del miércoles a las 8 PM es S=(α=2,β=1). Luego, cada día, hay una demanda aleatoria (entero no negativo) de bicicletas, donde la demanda se modela siguiendo distribuciones de Poisson (con parámetro de Poisson λ∈R>). Una demanda de i bicicletas para cada i=0,1,2⋯ ocurre con probabilidad:

Podemos visualizar esta distribución para ver la probabilidad de experimentar diferentes demandas, suponiendo que elijamos λ=2

# importamos matplotlib y algunos estilos deseadosimport matplotlib.pyplot as plt%matplotlib inlineplt.style.use("ggplot")plt.rcParams["figure.figsize"] = [10, 6]# necesitamos numpy para hacer algunos cálculos numéricosimport numpy as np# poisson se utiliza para encontrar la función de densidad de probabilidad de la distribución de Poisson from scipy.stats import poisson

x_values = np.arange(0,10)# función de densidad de probabilidad de la distribución de Poisson con lambda = 1pdf_x_values = poisson.pmf(k=x_values,mu=2)plt.bar(x_values, pdf_x_values, edgecolor='black')plt.xticks(np.arange(0, 10, step=1))plt.xlabel("Demanda del cliente")plt.ylabel("Probabilidad de la demanda del cliente")plt.title("Distribución de Probabilidad de la Demanda del Cliente con $\lambda = 1$ ")plt.savefig("fig/poisson_lambda_2.png", dpi=300)plt.show()
Probabilidad de experimentar diferentes demandas, Fuente: Autor

Construyendo la Transición de Probabilidad del Proceso de Markov:

Ahora que tenemos una comprensión inicial de lo que es un estado, St=(α,β), la incertidumbre que introduce el concepto de un proceso estocástico es la demanda del cliente (i). Podemos desarrollar cómo evoluciona la transición de probabilidad en este problema. Haré programación para eso, pero primero, expliquémoslo en términos más simples.

La transición de probabilidad de este problema tiene dos casos, caso 1 y caso 2.

  • Caso 1)

Si la demanda i es menor que el inventario total disponible ese día, inventario inicial=α+β

Ecuación de transición de probabilidad - Fuente: Autor
  • Caso 2)

Si la demanda i es mayor que el inventario total disponible ese día, inventario inicial=α+β

Ecuación de transición de probabilidad - Fuente: Autor

Donde F(α+β−1) es la función de distribución acumulada de la distribución de Poisson.

Habiendo entendido el contexto de este problema, ahora podemos escribir un código en Python para entenderlo mejor. El aspecto crucial de este código en Python es diseñar la estructura de datos para almacenar la transición del Proceso de Markov. Para hacer eso, estoy diseñando la estructura de datos como un Diccionario que llamo “MarkovProcessDict”. Las claves de este diccionario corresponden al estado actual y los valores (representados en un diccionario) son los siguientes estados, junto con las probabilidades asociadas a cada siguiente estado. Este es un ejemplo de cómo se ve la estructura de datos MarkovProcessDict:

from typing import DictMarkovProcessDict = {"Estado Actual A":{"Siguiente Estado 1, desde A": "Probabilidad del Siguiente Estado 1, desde A",                                        "Siguiente Estado 2, desde A": "Probabilidad del Siguiente Estado 2, desde A"},                                         "Estado Actual B":{"Siguiente Estado 1, desde B": "Probabilidad del Siguiente Estado 1, desde B",                                        "Siguiente Estado 2, desde B": "Probabilidad del Siguiente Estado 2, desde B" }}MarkovProcessDict
Fuente de la imagen: Autor

Desglosemos qué significa la estructura de datos MarkovProcessDict. Por ejemplo, el estado inicial es “Estado Actual A”, que puede ir a los dos nuevos estados:

  • 1) “Siguiente Estado 1, desde A”, con probabilidad “Probabilidad del Siguiente Estado 1, desde A
  • 2) “Siguiente Estado 2, desde A”, con probabilidad Probabilidad del Siguiente Estado 2, desde A”.

Código Práctico

Escribamos código para construir nuestra estructura de datos MarkovProcessDict, dadas dos casos diferentes de este proceso, explicados anteriormente.

MarkovProcessDict: Dict[tuple, Dict[tuple, float]] = {}user_capacity = 2user_poisson_lambda = 2.0

# Estamos considerando todos los posibles estados# Que podemos enfrentar en el funcionamiento de esta tienda de bicicletasfor alpha in range(user_capacity+1):                                                                                               for beta in range(user_capacity + 1 - alpha):                # Este es St, el estado actual        state = (alpha, beta)                                           # Esta es la inventario inicial, el total de bicicletas que tienes a las 8AM         initial_inventory = alpha + beta                                         # beta1 es el beta en el siguiente estado, independientemente del         #estado actual (ya que la política de decisión es constante)        beta1 = user_capacity - initial_inventory                # Lista de todas las posibles demandas que puedes obtener        for i in range(initial_inventory +1):            # si la demanda inicial puede satisfacer la demanda            if i <= (initial_inventory-1):                                # probabilidad de que suceda una demanda específica                transition_prob = poisson.pmf(i,user_poisson_lambda)                                # Si ya hemos definido el estado en nuestros datos                 # (MarkovProcessDict)                if state in MarkovProcessDict:                                        MarkovProcessDict[state][(initial_inventory - i, beta1)]= transition_prob                                else:                                        MarkovProcessDict[state] = {(initial_inventory - i, beta1):transition_prob }                                     # si la demanda inicial no puede satisfacer la demanda            else:                                # probabilidad de no satisfacer las demandas                transition_prob = 1- poisson.cdf(initial_inventory -1, user_poisson_lambda)                if state in MarkovProcessDict:                                        MarkovProcessDict[state][(0, beta1)]= transition_prob                                    else:                    MarkovProcessDict[state] = {(0, beta1 ):transition_prob }

En el código anterior, el bucle for recorre todas las combinaciones posibles de estados, y cada estado (St) se mueve al siguiente estado (S_{t+1}) con una probabilidad de “transition_prob”. Podemos imprimir la dinámica del sistema con el siguiente código:

or (state, value) in MarkovProcessDict.items():        print("El estado actual es: {}".format(state))        for (next_state, trans_prob) in value.items():        print("El siguiente estado es  {} con probabilidad de {:.2f}".format(next_state, trans_prob))
Imprimiendo código Python — Fuente de la imagen: Autor

Visualizando la Estructura de Datos Final

Una forma de comprender estas dinámicas es mediante el paquete de Python graphviz, donde cada nodo representa el Estado Actual, y las aristas muestran la probabilidad de moverse desde ese estado a otro.

# importar el paqueteimport graphviz  # definir la estructura inicial de un gráfico de graphviz, de color azul claro y estilo de llenado d = graphviz.Digraph(node_attr={'color': 'lightblue2', 'style': 'filled'},                     )d.attr(size='10,10')d.attr(layout = "circo")for s, v in MarkovProcessDict.items():        for s1, p in v.items():                        # representar alpha y beta con s[0] y s[1]            d.edge("(\u03B1={}, \u03B2={})".format(s[0],s[1]),                    # representar p como la probabilidad de moverse desde el estado actual al nuevo estado                    "(\u03B1={}, \u03B2={})".format(s1[0],s1[1]), label=str(round(p,2)), color="red")            print(d)
Imprimiendo código Python — Fuente de la imagen: Autor

En la gráfica a continuación, visualicé los gráficos de esta transición. Por ejemplo, si estamos en el estado, St = (α=1,β=0) (el círculo en la parte superior izquierda), hay un 86% de probabilidad de que el siguiente estado sea S(t+1):(α=0,β=1) y un 14% de probabilidad de que el siguiente estado sea S(t+1):(α=1,β=1).

Visualización del Proceso de Markov y las Transiciones de Estado — Fuente de la imagen: Autor

Notas Finales

  • La optimización de inventario no es un problema de optimización estática; más bien, es una toma de decisiones secuencial que necesita una política adaptativa para tomar la mejor decisión dada la incertidumbre en cada etapa de tiempo.
  • En este blog, intenté construir un modelo matemático para hacer un seguimiento del Proceso de Inventario (utilizando Estado y Proceso de Markov) y visualizar la dinámica del proceso con programación práctica en Python.
  • Este blog sienta las bases sobre cómo abordar problemas de optimización de inventario, donde en los próximos pasos, trabajaremos en Recompensa de Markov y Proceso de Decisión de Markov.

[1] Puedes leer este ejemplo con más profundidad en “Fundamentos del Aprendizaje por Refuerzo con Aplicación en Finanzas”. Sin embargo, he vuelto a escribir los códigos de Python en este blog para que sean más fáciles de entender.

¡Gracias por leer hasta ahora!

Espero que este artículo haya proporcionado un tutorial fácil de entender sobre cómo hacer la optimización de inventario con Python.

Si crees que este artículo te ayudó a aprender más sobre la optimización de inventario y el Proceso de Markov, ¡por favor dale un 👏 y sígueme!