Lee nuestro artículo sobre

class="lazyload

La optimización del surtido es un proceso fundamental en el sector minorista que consiste enseleccionar la combinación ideal de productospara satisfacer la demanda de los consumidores, teniendo en cuenta las numerosas limitaciones logísticas que ello conlleva. Los minoristas deben asegurarse de ofrecer los productos adecuados, en las cantidades adecuadas y en el momento adecuado. Al aprovechar data el conocimiento de los consumidores, los minoristas pueden tomar decisiones fundamentadas sobre qué artículos almacenar, cómo gestionar el inventario y a qué productos dar prioridad en función de las preferencias de los clientes, las tendencias estacionales y los patrones de venta.

Para los comercios minoristas, la optimización del surtido es fundamental para lograr un equilibrio entrevariedadyeficiencia. Ofrecer muy pocas opciones puede ahuyentar a los clientes, mientras que ofrecer demasiadas puede generar confusión, exceso de existencias y una reducción de los márgenes de beneficio. La optimización del surtido de productos ayuda a las empresas a mejorar la satisfacción de los clientes, garantizando la disponibilidad de los artículos más demandados y eliminando al mismo tiempo los productos con bajo rendimiento que ocupan un valioso espacio en las estanterías.

El modelado de decisioneses una forma eficaz de abordar la optimización del surtido, ya que ofrece un marco data para comprender las preferencias de los clientes y predecir cómo elegirán entre los distintos productos. Al analizar diversos factores, como la sensibilidad al precio, las características de los productos y la fidelidad a la marca, el modelado de decisiones ayuda a los minoristas a identificar qué productos tienen más probabilidades de satisfacer la demanda de los clientes.

En definitiva, los modelos de selección permiten a los minoristas ofrecer la combinación adecuada de productos, adaptar los surtidos a segmentos específicos de clientes y optimizar el espacio en las estanterías para impulsar la rentabilidad o incluso la fijación de precios de los artículos.

Si nunca has oído hablar del modelado de elección, puedes leernuestro artículo, en el que se presentan los conceptos clave con ejemplos. En este artículo, nos centraremos principalmente en cómo se pueden utilizar los modelos de elección discreta para optimizar una gama de productos. Ofrecemos ejemplos de código basados en la bibliotecachoice-learn, diseñada para ayudar a data en este tipo de casos de uso.

El código proporcionado utiliza el paquete de Python «choice-learn» y se puede encontrar en un cuaderno aquí.

Configuración: Instalación de Python y Choice-Learn

En este artículo, ofrecemos fragmentos de código que acompañan a las explicaciones. El código utiliza la bibliotecaChoice-Learn, que ofrece herramientas eficaces para el modelado de decisiones y diversas aplicaciones, como la optimización de surtidos o la fijación de precios. Choice-Learn está disponible a través de PyPI; puedes descargarla fácilmente con


pip install choice-learn

El conjunto de datos: recibos de venta

Utilizaremos el conjunto de datos TaFeng sobre productos alimenticios. Puedes descargarlo deKaggley abrirlo en tu entorno de Python con choice-learn:

import load_tafeng de choice_learn.datasets
tafeng_df = load_tafeng(as_frame=True)
print(tafeng_df.head())
class="lazyload

El conjunto de datos consta de más de 800 000 compras individuales realizadas en una tienda de alimentación china. Para cada compra se proporcionan diversos datos, entre los que se incluyen 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 rara vez se venden. Con el fin de optimizar la logística, el minorista puede optar por reducir el número de productos que ofrece. El objetivo en este caso es identificar el conjunto óptimo de artículos que se deben vender.

Para lograrlo, 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 a la hora de configurar un surtido más eficiente y rentable.Cabe señalar que hacemos esto principalmente para simplificar el ejemplo y que, en realidad, se podrían mantener todos los artículos.

# Conservar solo los 20 productos más vendidos
tafeng_df = tafeng_df.loc[
tafeng_df.PRODUCT_ID.isin(tafeng_df.PRODUCT_ID.value_counts().index[:20])
].reset_index(drop=True)
# Eliminar valores NaN
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)
print(tafeng_df.head())

Codifiquemos también las categorías de edad con valores «one-hot» cada diez años:

# Codificación de los grupos de edad
tafeng_df[“twenties”] = tafeng_df.apply(lambda row: 1 if row[“AGE_GROUP”] == “25-29” else 0,axis=1)
tafeng_df[“thirties”] = tafeng_df.apply(
lambda row: 1 if row[“AGE_GROUP”] in ([“30-34”, “35-39”]) else 0,axis=1
)
tafeng_df[“forties”] = tafeng_df.apply(
lambda row: 1 if row[“AGE_GROUP”] in ([“40-44”, “45-49”]) else 0,axis=1
)
tafeng_df[“fifties”] = tafeng_df.apply(
lambda row: 1 if row[“AGE_GROUP”] in ([“50-54”, “55-59”]) else 0,axis=1
)
tafeng_df[“sixties_and_above”] = tafeng_df.apply(
lambda row: 1 if row[“AGE_GROUP”] in ([“60-64”, “>65”]) else 0,axis=1
)

Ahora que nuestros data listos, tenemos que crear unChoiceDataset, el objeto data dechoice-learn. Para ello, hay que especificar las características que describen el contexto en el que se realiza una compra:

  • Características de los clientes(rasgos comunes): el grupo de edad
  • Características del producto(características del artículo): el precio del artículo

Un aspecto clave de los modelos de elección es que necesitamos conocer las características detodos los artículos disponibles en el momento de la compra, no solo las del artículo elegido. Esto nos permite analizar cómo influyen los precios de los distintos productos en la decisión del cliente. Dado que esta información no está disponible directamente en el conjunto de datos, partimos de la hipótesis de que, en cada compra, los precios de los demás artículos siguen siendo los mismos que en la venta anterior.

# ID de producto a índice
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
prices = [[0] for _ in range(len(id_to_index))] for k, v in id_to_index.items():
prices[v][0] = tafeng_df.loc[tafeng_df.PRODUCT_ID == k].SALES_PRICE.to_numpy()[0] # Creamos las matrices que constituirán el ChoiceDataset
shared_features = [] items_features = [] choices = [] # Para cada artículo 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[row.PRODUCT_ID] prices[item_index][0] = row.SALES_PRICE
shared_features.append(
row[["twenties", "thirties", "forties", "fifties", "sixties_and_above"]].to_numpy()
)
items_features.append(prices)
choices.append(item_index)

Ahora que ya tenemos toda la información, podemoscrear el ChoiceDataset:

fromdata import ChoiceDataset
dataset = ChoiceDataset(
shared_features_by_choice=shared_features,
shared_features_by_choice_names=[‘twenties’, ‘thirties’, ‘forties’, ‘fifties’, ‘sixties_and_above’],
características_de_los_artículos_por_elección=características_de_los_artículos,
nombres_de_las_características_de_los_artículos_por_elección=[“PRECIO_DE_VENTA”],
opciones=opciones
)

Definición y estimación del modelo de elección

Desarrollaremos y estimaremos un modelo de elección que prediga la probabilidad de que un cliente seleccione un artículo concreto de entre toda una gama de productos similares. A partir del conjunto de datos disponible, definimos la siguiente función de utilidad para un artículoiconsiderado por un clientej:

class="lazyload

Esta función representa la utilidad (o satisfacción) que obtiene un cliente al elegir un artículo concreto, en función tanto de su edad como del precio del artículo.

Para obtener más detalles sobre cómo formulamos una función de utilidad, consulta nuestra primerapublicación. Ten en cuenta que otro modelo lógico —que no se ha presentado para simplificar el análisis— podría consistir en estimar una sensibilidad al precio por cada categoría de edad.

Este es el código para estimar dicho modelo con choice-learn:

import ConditionalLogit de choice_learn.models
model = ConditionalLogit(optimizer=“Adam”,batch_size=1024,epochs=300,lr=0.002)
for age_category in [“twenties”, “thirties”, “forties”, “fifties”, “sixties_and_above”]:
model.add_coefficients(
coefficient_name=age_category, feature_name=age_category,items_indexes=list(range(20))
)
model.add_shared_coefficient(
coefficient_name="price", feature_name="SALES_PRICE",items_indexes=list(range(20))
)
hist = model.fit(dataset)

Puedes comprobar que el modelo se ajusta bien al conjunto de datos:

import matplotlib.pyplot as plt
plt.plot(hist[“train_loss”])
plt.xlabel(“Época”)
plt.ylabel(“Logaritmo negativo de la verosimilitud”)
plt.show(
class="lazyload

Encontrar el surtido óptimo

Una vez que disponemos de las probabilidades de compra, podemos calcular los ingresos medios por cliente del surtidoA utilizandola fórmula:

class="lazyload

Para encontrar el surtido que maximice los ingresos, podríamos evaluar todas las combinaciones posibles y seleccionar aquella con los ingresos medios más elevados. Sin embargo, un enfoque más eficiente consiste en utilizarla programación lineal (PL). En este caso, nos centraremos en cómo utilizar la implementación«choice-learn»del optimizador de surtidos.

Es importante distinguir entre maximizar los ingresos y maximizar los márgenes de beneficio. Si bien los ingresos son importantes, los márgenes de beneficio tienen en cuenta los costes asociados a cada producto. Dependiendo de tu objetivo, tal vez te interese optimizar los beneficios en lugar de los ingresos puros.

Para optimizar el surtido, debemos aportar varios datos clave:

  • La ponderación que queremos asignar a cada categoría de edad; utilicemos su cuota de clientes
  • La utilidad de cada elemento (calculada mediante nuestro modelo de elección) para cada categoría de edad
  • El valor que hay que optimizar para cada elemento (en este caso, los ingresos)
  • El tamaño del surtido (por ejemplo, 12 artículos)

Así es como funciona conchoice-learn:


from choice_learn.toolbox.assortment_optimizer import LatentClassAssortmentOptimizer;
# Precio de cada artículo;
future_prices = np.stack([items_features[-1]]*5,axis=0);
age_category = np.eye(5).astype("float32")
# Calcular la utilidad de cada artículo dado su precio y cada categoría de edad
predicted_utilities = model.compute_batch_utility(shared_features_by_choice=age_category,
                                                  items_features_by_choice=future_prices,
                                                  available_items_by_choice=np.ones((5, 20)),
                                                 choices=None
                                                  )
age_category_weights = np.sum(shared_features,axis=0) / len(shared_features)
opt = LatentClassAssortmentOptimizer(
solver="or-tools", # Solucionador a utilizar, ya sea "or-tools" o "gurobi" (si tienes una licencia)
class_weights=age_category_weights, # Pesos de cada clase
class_utilities=np.exp(predicted_utilities), # utilidades en la forma (n_classes, n_items)
itemwise_values=future_prices[0][:, 0], # Valores a optimizar para cada artículo; en este caso, el precio que se utiliza para calcular la rotación
assortment_size=12) # Tamaño del surtido que queremos
assortment, opt_obj = opt.solve()

Al ejecutar el código, deberías obtener algo parecido a esto:


class="lazyload

El surtido óptimo para maximizar los ingresos viene indicado por los índices de los valores 1 del vector. Este surtido genera, en teoría, unos ingresos medios por cliente de 134 yuanes. Puedes explorar otras combinaciones, pero todas ellas darán lugar a 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 establece 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, es posible que tengas que tener en cuenta las limitaciones de espacio en las estanterías de tu tienda. En ese caso, puedes optimizar el surtido de manera que el volumen total de los artículos no supere el espacio disponible en las estanterías. Esta restricción adicional, junto con otras como las estrategias de precios, se ilustraaquí.


Conclusión

Si estás trabajando en la optimización del surtido o en la fijación de precios, el modelado de decisiones es una herramienta fantástica; no dejes de echarle un vistazo. Choice-Learn ofrece muchos ejemplos interesantes en suGitHub. ¡Échale un vistazo y dale a «Me gusta» si te resulta útil!