La optimización del surtido es un proceso fundamental en el comercio minorista que consiste en confeccionar la combinación ideal de productos para satisfacer la demanda de los consumidores, teniendo en cuenta al mismo tiempo las numerosas limitaciones logísticas existentes. Los minoristas deben asegurarse de ofrecer los productos adecuados, en las cantidades adecuadas y en el momento oportuno. Al aprovechar data y la información sobre los consumidores, los minoristas pueden tomar decisiones informadas sobre qué artículos almacenar, cómo gestionar el inventario y qué productos priorizar en función de las preferencias de los clientes, las tendencias estacionales y los patrones de ventas.
Para las empresas minoristas, la optimización del surtido es esencial para lograr un equilibrio entre variedad y eficiencia. Ofrecer muy pocas opciones puede ahuyentar a los clientes, mientras que ofrecer demasiadas puede generar confusión, exceso de inventario y menores márgenes de beneficio. La optimización del surtido de productos ayuda a las empresas a mejorar la satisfacción del cliente garantizando la disponibilidad de los artículos más populares y eliminando los productos de bajo rendimiento que ocupan un valioso espacio en las estanterías.
El modelo de elección es una forma eficaz de abordar la optimización del surtido porque proporciona un marco data para comprender las preferencias de los clientes y predecir cómo elegirán entre distintos productos. Mediante el análisis de diversos factores, como la sensibilidad al precio, las características del producto y la fidelidad a la marca, el modelado de elección ayuda a los minoristas a identificar qué productos tienen más probabilidades de satisfacer la demanda de los clientes.
En última instancia, el modelado de la elección permite a los minoristas ofrecer la combinación adecuada de productos, adaptar los surtidos a segmentos específicos de clientes, y también puede optimizar el espacio en los lineales para impulsar la rentabilidad o incluso el precio de los artículos.
Si nunca ha oído hablar de los modelos de elección, puede leer nuestro artículo que presenta los conceptos clave con ejemplos. En este artículo, nos centraremos principalmente en cómo pueden utilizarse los modelos de elección discreta para optimizar un surtido de productos. Proporcionamos ejemplos de código basados en la biblioteca choice-learn, diseñada para ayudar a los científicos data datos en estos casos de uso.
El código proporcionado utiliza el paquete choice-learn de Python y puede encontrarse en un cuaderno aquí.
Configurar: Instalación de Python y Choice-Learn
En este artículo, proporcionamos fragmentos de código para acompañar las explicaciones. El código utiliza la biblioteca Choice-Learn, que proporciona herramientas eficaces para el modelado de elecciones y varias aplicaciones, como la optimización del surtido o el precio. Choice-Learn está disponible a través de PyPI, puedes obtenerla simplemente con
El conjunto de datos : ingresos por ventas
Utilizaremos el conjunto de datos TaFeng grocery. Puedes descargarlo de Kaggle y abrirlo en tu entorno Python con choice-learn:
print(tafeng_df.head())
El conjunto de datos consta de más de 800.000 compras individuales en un supermercado chino. Para cada compra, se proporcionan varios detalles, incluido el artículo comprado (PRODUCT_ID), el precio al que se vendió (SALES_PRICE) y el grupo de edad del cliente (AGE_GROUP).
Se puede observar que se ofrecen muchos artículos diferentes y que algunos de ellos se venden raramente. Para racionalizar la logística, el minorista puede optar por reducir el número de productos que ofrece. El objetivo en este caso es identificar el subconjunto óptimo de artículos a vender.
Para ello, nos centramos en los artículos más vendidos, ya que es más probable que se vuelvan a comprar y desempeñarán un papel crucial en la configuración de un surtido más eficiente y rentable. Tenga en cuenta que lo hacemos principalmente para simplificar el ejemplo y que podrían conservarse todos los artículos.
tafeng_df = tafeng_df.loc[
tafeng_df.PRODUCT_ID.isin(tafeng_df.PRODUCT_ID.value_counts().index[:20])
].reset_index(drop=True)
tafeng_df = tafeng_df.loc[
tafeng_df.AGE_GROUP.isin(["25-29", "40-44", "45-49", ">65", "30-34", "35-39", "50-54", "55-59", "60-64"]. )
].reset_index(drop=True)
Codifiquemos también las categorías de edad con un valor caliente cada diez años:
tafeng_df["veinteañeros"]= tafeng_df.apply(lambda fila: 1 if fila["GRUPO_Edad"]== "25-29" else 0, eje=1)
tafeng_df["treintañeros"]= tafeng_df.apply(
lambda fila: 1 if fila["GRUPO_EAD"] en (["30-34", "35-39"]) else 0, eje=1
)
tafeng_df["cuarenta"]= tafeng_df.apply(
lambda fila: 1 if fila["GRUPO_Edad"] in (["40-44", "45-49"]) else 0, eje=1
)
tafeng_df["cincuentones"]= tafeng_df.apply(
lambda fila: 1 if fila["GRUPO_Edad"] in (["50-54", "55-59"]) else 0, eje=1
)
tafeng_df["sesenta_y_mayores"]= tafeng_df.apply(
lambda fila: 1 if fila["GRUPO_Edad"] in (["60-64", ">65"]) else 0, eje=1
)
Ahora que nuestros data están listos, necesitamos crear un ChoiceDataset, el objeto manejador de data en choice-learn. Esto implica especificar las características que describen el contexto en el que se realiza una compra:
- Características de los clientes (rasgos compartidos): la categoría de edad
- Características del producto (características del artículo): el precio del artículo
Un aspecto clave de la modelización de la elección es que necesitamos las características de todos los artículos disponibles en el momento de la compra, no sólo del elegido. Esto nos permite analizar cómo influyen los precios de los distintos productos en la decisión del cliente. Como esta información no está disponible directamente en el conjunto de datos, suponemos que, en cada compra, los precios de los demás artículos siguen siendo los mismos que en la venta anterior.
id_to_index =
for i, product_id in enumerate(np.sort(tafeng_df.PRODUCT_ID.unique())):
id_to_index[product_id] = i
# Inicializar el precio de los artículos
precios = [[0] for _ in range(len(id_to_index))] for k, v in id_to_index.items():
precios[v][0] = tafeng_df.loc[tafeng_df.PRODUCT_ID == k].SALES_PRICE.to_numpy()[0] # Crear las matrices que constituirán el ChoiceDataset
características_compartidas = [] items_features = [] opciones = [] # Para cada ítem comprado, guardamos
# - la representación de la edad (one-hot) del cliente
# - el precio de todos los artículos vendidos
for i, row in tafeng_df.iterrows():
item_index = id_to_index[fila.PRODUCT_ID] precios[item_index][0] = fila.PRECIO_VENTA
shared_features.append(
fila["veinteañeros", "treintañeros", "cuarentones", "cincuentones", "sesentones_y_más"]].to_numpy()
)
items_features.append(precios)
choices.append(item_index)
Ahora que tenemos toda nuestra información, podemos crear el ChoiceDataset:
dataset = ChoiceDataset(
características_compartidas_por_elección=características_compartidas,
shared_features_by_choice_names=['veintes', 'thirties', 'forties', 'fifties', 'sixties_and_above'],
items_features_by_choice=items_features,
items_features_by_choice_names=["PRECIO_VENTA"],
choices=opciones
)
Definición y estimación del modelo de elección
Desarrollaremos y estimaremos un modelo de elección que predice la probabilidad de que un cliente seleccione un artículo concreto de entre todo un surtido de productos similares. Basándonos en el conjunto de datos disponible, definimos la siguiente función de utilidad para un artículo i considerado por un cliente j:
Esta función representa la utilidad (o satisfacción) que obtiene un cliente al elegir un determinado artículo, influida tanto por la edad del cliente como por el precio del artículo.
Para más detalles sobre cómo formulamos una función de utilidad, consulte nuestro primer post. Obsérvese que otro modelo lógico -pero no presentado para simplificar- podría ser estimar una sensibilidad al precio por categoría de edad.
Aquí está el código para estimar tal modelo con choice-learn:
model.add_coefficients(
nombre_coeficiente=categoría_edad, nombre_característica=categoría_edad, items_indexes=list(range(20))
)
coefficient_name="precio", feature_name="PRECIO_VENTA",items_indexes=list(range(20))
)
Puede comprobar que el modelo se ajusta bien al conjunto de datos:
plt.plot(hist["pérdida_entrenamiento"])
plt.xlabel("Época")
plt.ylabel("Probabilidad logarítmica negativa")
plt.show(
Encontrar el surtido óptimo
Con las probabilidades de compra en la mano, ahora podemos estimar el ingreso medio por cliente de un surtido A utilizando la fórmula:
Para encontrar el surtido que maximice los ingresos, podríamos evaluar todas las combinaciones posibles y seleccionar la que tenga los ingresos medios más elevados. Sin embargo, un enfoque más eficaz es utilizar programación lineal (PL). Aquí nos centraremos en cómo utilizar la implementación choice-learn del optimizador de surtido.
Es importante distinguir entre maximizar los ingresos y maximizar los márgenes de beneficio. Aunque los ingresos son importantes, los márgenes de beneficio tienen en cuenta los costes asociados a cada producto. Dependiendo de su objetivo, es posible que desee optimizar los beneficios en lugar de los ingresos puros.
Para optimizar el surtido, necesitamos varios datos clave:
- El peso que queremos dar a cada categoría de edad, vamos con su cuota de clientes
- La utilidad de cada artículo (calculada por nuestro modelo de elección) para cada categoría de edad.
- El valor a optimizar para cada elemento (en este caso, los ingresos)
- El tamaño del surtido (por ejemplo, 12 artículos)
Así es como funciona utilizando la elección-aprendizaje:
from choice_learn.toolbox.assortment_optimizer import LatentClassAssortmentOptimizer
# Precio de cada artículo
precios_futuros = np.stack([items_features[-1]]*5, axis=0)
categoría_edad = np.eye(5).astype("float32")
# Calcular la utilidad de cada artículo dado su precio y cada categoría de edad
utilidades_predecidas = model.compute_batch_utility(shared_features_by_choice=categoría_edad,
items_features_by_choice=precios_futuros,
artículos_disponibles_por_elección=np.ones((5, 20)),
opciones=Ninguna
)
age_category_weights = np.sum(shared_features, axis=0) / len(shared_features)
opt = LatentClassAssortmentOptimizer(
solver=" or-tools", # Solver a utilizar, ya sea "or-tools" o "gurobi" (si tiene licencia)
class_weights=age_category_weights, # Pesos de cada clase
class_utilities=np.exp(predicted_utilities), # utilidades en la forma (n_clases, n_artículos)
itemwise_values=future_prices[0][:, 0], # Valores a optimizar para cada artículo, aquí el precio que se utiliza para calcular la rotación
tamaño_surtido=12) # Tamaño del surtido que queremos
surtido, opt_obj = opt.solve()
Ejecutando el código deberías tener algo como
El surtido óptimo para maximizar los ingresos se indica con los índices de los valores 1 del vector. Teóricamente, este surtido produce unos ingresos medios por cliente de 134 yuanes. Puede explorar otras combinaciones, pero todas darán como resultado unos ingresos medios inferiores.
Otro objetivo podría ser maximizar el número de ventas. En este caso, el valor de optimización por artículo se fija en 1 para todos los artículos, lo que da lugar a un surtido óptimo diferente.
La eficacia de este método se hace evidente cuando se introducen restricciones adicionales. Por ejemplo, puede que tenga que tener en cuenta las limitaciones de espacio en las estanterías de su tienda. En este caso, puede optimizar un surtido cuyo tamaño total de artículos no supere el espacio disponible en las estanterías. Esta restricción adicional, junto con otras como las estrategias de precios, se demuestra aquí.
Conclusión
Si estás trabajando en la optimización del surtido o la fijación de precios, el modelado de elección es una gran herramienta, asegúrate de echarle un vistazo. Choice-Learn ofrece muchos ejemplos interesantes en su GitHub. Échale un vistazo y deja una estrella si te resulta útil.

BLOG












