L'optimisation de l'assortiment est un processus essentiel dans le secteur de la vente au détail qui consiste àsélectionner la combinaison idéale de produitsafin de répondre à la demande des consommateurs tout en tenant compte des nombreuses contraintes logistiques. Les détaillants doivent s'assurer de proposer les bons produits, en quantités adéquates et au moment opportun. En s'appuyant sur data les informations sur les consommateurs, ils peuvent prendre des décisions éclairées quant aux articles à stocker, à la gestion des stocks et aux produits à privilégier, en fonction des préférences des clients, des tendances saisonnières et des schémas de vente.
Pour les commerces de détail, l'optimisation de l'assortiment est essentielle pour trouver le juste équilibre entrevariétéetefficacité. Proposer trop peu de choix peut faire fuir les clients, tandis qu'en proposer trop peut être source de confusion, entraîner des excédents de stock et réduire les marges bénéficiaires. L'optimisation de l'assortiment de produits aide les entreprises à améliorer la satisfaction client en garantissant la disponibilité des articles les plus demandés, tout en éliminant les produits peu performants qui occupent un espace précieux en rayon.
La modélisation des choixconstitue une méthode efficace pour optimiser la gamme de produits, car elle offre un cadre data permettant de comprendre les préférences des clients et de prédire leurs choix entre différents produits. En analysant divers facteurs tels que la sensibilité au prix, les caractéristiques des produits et la fidélité à la marque, la modélisation des choix aide les détaillants à identifier les produits les plus susceptibles de répondre à la demande des clients.
En fin de compte, la modélisation des choix permet aux détaillants de proposer une gamme de produits adaptée, d'adapter leurs assortiments à des segments de clientèle spécifiques, et peut également optimiser l'espace en rayon afin d'améliorer la rentabilité, voire de déterminer le prix des articles.
Si vous n'avez jamais entendu parler de la modélisation des choix, vous pouvez consulternotre articlequi présente les concepts clés à l'aide d'exemples. Dans cet article, nous nous intéresserons principalement à la manière dont les modèles de choix discrets peuvent être utilisés pour optimiser une gamme de produits. Nous fournissons des exemples de code basés sur la bibliothèquechoice-learn, conçue pour aider data dans ce type de cas d'utilisation.
Le code fourni utilise le module Python « choice-learn » et est disponible dans un notebook ici.
Configuration : installation de Python et de Choice-Learn
Dans cet article, nous proposons des extraits de code pour illustrer nos explications. Le code utilise la bibliothèqueChoice-Learn, qui offre des outils efficaces pour la modélisation des choix et diverses applications, telles que l'optimisation de l'assortiment ou la tarification. Choice-Learn est disponible sur PyPI ; vous pouvez l'obtenir simplement avec
L'ensemble de données : les tickets de caisse
Nous utiliserons l'ensemble de données TaFeng sur les produits alimentaires. Vous pouvez le télécharger depuisKaggleet l'ouvrir dans votre environnement Python à l'aide de choice-learn :
print(tafeng_df.head())
L'ensemble de données comprend plus de 800 000 achats individuels effectués dans une épicerie chinoise. Pour chaque achat, diverses informations sont fournies, notamment l'article acheté (PRODUCT_ID), son prix de vente (SALES_PRICE) et la tranche d'âge du client (AGE_GROUP).
On constate qu'un large éventail d'articles est proposé, dont certains se vendent rarement. Afin de rationaliser la logistique, le détaillant peut choisir de réduire le nombre de produits proposés. L'objectif, dans ce cas, est d'identifier l'ensemble optimal d'articles à vendre.
Pour y parvenir, nous nous concentrons sur les articles les plus vendus, car ce sont eux qui ont le plus de chances d'être rachetés et qui joueront un rôle crucial dans la constitution d'un assortiment plus efficace et plus rentable.Notez que nous procédons ainsi principalement pour simplifier l'exemple et que tous les articles pourraient être conservés.
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)
Encodons également les tranches d'âge en utilisant la méthode « one-hot » tous les dix ans :
tafeng_df[« twenties »] = tafeng_df.Postuler(lambda row: 1 if row[« AGE_GROUP »] == « 25-29 » else 0,axis=1)
tafeng_df[« thirties »] = tafeng_df.Postuler(
lambda row: 1 if row[“AGE_GROUP”] in ([“30-34”, “35-39”]) else 0,axis=1
)
tafeng_df[« forties »] = tafeng_df.Postuler(
lambda row: 1 if row[« AGE_GROUP »] in ([« 40-44 », « 45-49 »]) else 0,axis=1
)
tafeng_df[“fifties”] = tafeng_df.Postuler(
lambda row: 1 if row[“AGE_GROUP”] in ([“50-54”, “55-59”]) else 0,axis=1
)
tafeng_df[“sixties_and_above”] = tafeng_df.Postuler(
lambda row: 1 if row[“AGE_GROUP”] in ([“60-64”, “>65”]) else 0,axis=1
)
Maintenant que nos data prêtes, nous devons créer unChoiceDataset, l'objet data danschoice-learn. Cela implique de spécifier les caractéristiques qui décrivent le contexte dans lequel un achat est effectué :
- Caractéristiques des clients(points communs) : la tranche d'âge
- Caractéristiques du produit(détails de l'article) : le prix de l'article
Un aspect essentiel de la modélisation des choix réside dans le fait que nous avons besoin des caractéristiques detous les articles disponibles au moment de l'achat, et pas seulement de celui qui a été choisi. Cela nous permet d'analyser comment les prix des différents produits influencent la décision du client. Comme ces informations ne sont pas directement disponibles dans l'ensemble de données, nous partons du principe que, pour chaque achat, les prix des autres articles restent identiques à ceux de la vente précédente.
id_to_index =
for i, product_id in enumerate(np.sort(tafeng_df.PRODUCT_ID.unique())):
id_to_index[product_id] = i
# Initialisation des prix des articles
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] # Créer les tableaux qui constitueront le ChoiceDataset
shared_features = [] items_features = [] choices = [] # Pour chaque article acheté, nous enregistrons :
# – la représentation de l'âge (one-hot) du client
# – le prix de tous les articles vendus
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)
Maintenant que nous disposons de toutes les informations nécessaires, nous pouvonscréer le ChoiceDataset:
dataset = ChoiceDataset(
shared_features_by_choice=shared_features,
shared_features_by_choice_names=[‘twenties’, ‘thirties’, ‘forties’, ‘fifties’, ‘sixties_and_above’],
items_features_by_choice=items_features,
items_features_by_choice_names=[“SALES_PRICE”],
choices=choices
)
Définition et estimation du modèle de choix
Nous allons élaborer et estimer un modèle de choix permettant de prédire la probabilité qu'un client sélectionne un article spécifique parmi un assortiment complet de produits similaires. À partir de l'ensemble de données disponible, nous définissons la fonction d'utilité suivante pour un articleienvisagé par un clientj :
Cette fonction représente l'utilité (ou la satisfaction) qu'un client tire du choix d'un article donné, en fonction à la fois de son âge et du prix de l'article.
Pour plus de détails sur la manière dont nous formulons une fonction d'utilité, consultez notre premierarticle. Notez qu'un autre modèle, tout aussi logique — mais que nous n'avons pas présenté ici par souci de simplicité —, consisterait à estimer une sensibilité au prix par tranche d'âge.
Voici le code permettant d'estimer un tel modèle à l'aide de choice-learn :
model.add_coefficients(
coefficient_name=age_category, feature_name=age_category,items_indexes=list(range(20))
)
coefficient_name=« price »,feature_name=« SALES_PRICE »,items_indexes=list(range(20))
)
Vous pouvez vérifier que le modèle s'adapte bien à l'ensemble de données :
plt.plot(hist[« train_loss »])
plt.xlabel(« Époque »)
plt.ylabel(« Log-vraisemblance négative »)
plt.show(
Déterminer l'assortiment optimal
Une fois les probabilités d'achat connues, nous pouvons désormais estimer le chiffre d'affaires moyen par client d'un assortimentA à l'aide dela formule suivante :
Pour déterminer l'assortiment qui maximise le chiffre d'affaires, nous pourrions évaluer toutes les combinaisons possibles et sélectionner celle qui génère le chiffre d'affaires moyen le plus élevé. Cependant, une approche plus efficace consiste à recourir àla programmation linéaire (PL). Nous nous concentrerons ici sur l'utilisation de l'implémentation« choice-learn »de l'optimiseur d'assortiment.
Il est important de faire la distinction entre la maximisation du chiffre d'affaires et celle des marges bénéficiaires. Si le chiffre d'affaires est important, les marges bénéficiaires tiennent compte des coûts liés à chaque produit. En fonction de votre objectif, vous pourriez préférer optimiser vos bénéfices plutôt que votre chiffre d'affaires à proprement parler.
Pour optimiser la gamme de produits, nous devons fournir plusieurs informations essentielles :
- La pondération que nous souhaitons attribuer à chaque tranche d'âge : prenons leur part de clientèle
- L'utilité de chaque élément (calculée par notre modèle de choix) pour chaque tranche d'âge
- La valeur à optimiser pour chaque élément (dans ce cas, le chiffre d'affaires)
- La taille de l'assortiment (par exemple, 12 articles)
Voici comment cela fonctionne avecchoice-learn:
from choice_learn.toolbox.assortment_optimizer import LatentClassAssortmentOptimizer
# Prix de chaque article
future_prices = np.stack([items_features[-1]]*5,axis=0)
age_category = np.eye(5).astype("float32")
# Calculer l'utilité de chaque article en fonction de son prix et de chaque catégorie d'âge
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", # Solveur à utiliser, soit « or-tools » soit « gurobi » (si vous disposez d'une licence)
class_weights=age_category_weights, # Poids de chaque classe
class_utilities=np.exp(predicted_utilities), # utilités de forme (n_classes, n_items)
itemwise_values=future_prices[0][:, 0], # Valeurs à optimiser pour chaque article, ici le prix utilisé pour calculer le chiffre d'affaires
assortment_size=12) # Taille de l'assortiment souhaitée
assortment, opt_obj = opt.solve()
Une fois le code exécuté, vous devriez obtenir quelque chose comme :
L'assortiment optimal pour maximiser le chiffre d'affaires est indiqué par les indices égaux à 1 dans le vecteur. Cet assortiment génère théoriquement un chiffre d'affaires moyen par client de 134 yuans. Vous pouvez explorer d'autres combinaisons, mais elles se traduiront toutes par un chiffre d'affaires moyen inférieur.
Un autre objectif pourrait être de maximiser le nombre de ventes. Dans ce scénario, la valeur d'optimisation attribuée à chaque article est fixée à 1 pour tous les articles, ce qui conduit à un assortiment optimal différent.
L'efficacité de cette méthode apparaît clairement lorsque l'on ajoute des contraintes supplémentaires. Par exemple, vous devrez peut-être tenir compte des contraintes d'espace sur les rayons de votre magasin. Dans ce cas, vous pouvez optimiser votre assortiment de manière à ce que l'encombrement total des articles ne dépasse pas l'espace disponible sur les rayons. Cette contrainte supplémentaire, ainsi que d'autres telles que les stratégies de tarification, sont illustréesici.
Conclusion
Si vous travaillez sur l'optimisation de l'assortiment ou la tarification, la modélisation des choix est un excellent outil : n'hésitez pas à vous y intéresser. Choice-Learn propose de nombreux exemples intéressants sur sonGitHub. Allez y jeter un œil et n'hésitez pas à l'ajouter à vos favoris si vous le trouvez utile !

BLOG












