Une famille de modèles qui apprend un ordre plutôt qu'une note : quels produits afficher en premier pour une recherche donnée. Le modèle combine pertinence du texte, avis, ventes, prix ou stock, et optimise directement la qualité du haut de la liste. LambdaMART, un boosting d'arbres, est le standard des moteurs de recherche.
Un chef de rayon ne note pas chaque produit dans l'absolu. Pour chaque demande de client, il décide lequel mettre devant l'autre, et il apprend de ses erreurs d'ordre.
Pour chaque recherche passée, on garde les produits proposés et leur pertinence observée : ignoré, cliqué, ajouté au panier, acheté (de 0 à 3).
LambdaMART construit des arbres qui corrigent les erreurs d'ordre entre paires de produits d'une même recherche, en pesant plus lourd les erreurs en haut de liste.
Pour une nouvelle recherche, le modèle donne un score à chaque produit candidat. Seul l'ordre des scores compte : on affiche du plus haut au plus bas.
Pour chaque produit candidat : score de pertinence du texte, note moyenne, ventes des 30 derniers jours, prix relatif, disponibilité. La pertinence observée va de 0 (ignoré) à 3 (acheté). Les données sont simulées.
Le modèle apprend à faire remonter les produits en stock, bien notés et au bon prix, et pas seulement ceux dont le texte colle à la requête.
Il mesure la qualité des 10 premiers résultats, avec plus de poids aux premières places : 1 correspond à l'ordre idéal. On le compare au tri actuel, ici le seul score texte, sur des recherches jamais vues par le modèle.
Noms donnés pour LightGBM, identiques en R et en Python.
Choisit l'apprentissage par listes (LambdaMART). XGBoost propose l'équivalent avec rank:ndcg.
Nombre de lignes de chaque recherche, dans l'ordre des données. Une erreur ici, et le modèle compare des produits de recherches différentes.
Profondeur à laquelle le NDCG est suivi pendant l'entraînement : 10 pour une première page de résultats, 3 pour un bandeau de recommandations.
Comme pour tout boosting : un pas petit avec davantage d'arbres, des arbres de taille modérée. On règle par validation sur des recherches mises de côté.
# Classement des résultats de recherche : Learning to Rank (LambdaMART) en R
library(lightgbm)
# Simulation : 300 recherches, 20 produits candidats chacune
set.seed(42)
n_req <- 300
n_prod <- 20
N <- n_req * n_prod
requete <- rep(1:n_req, each = n_prod)
X <- cbind(score_texte = runif(N), note_moyenne = runif(N, 2.5, 5), ventes_30j = rpois(N, 20),
prix_relatif = runif(N, 0.6, 1.6), en_stock = rbinom(N, 1, 0.85))
latent <- 2.5 * X[, "score_texte"] + 0.8 * (X[, "note_moyenne"] - 3.75) + 0.02 * X[, "ventes_30j"] -
(X[, "prix_relatif"] - 1) + 1.5 * X[, "en_stock"] + rnorm(N, 0, 0.5)
pertinence <- findInterval(latent, quantile(latent, c(0.6, 0.8, 0.93))) # 0 = ignoré ... 3 = acheté
# 240 recherches pour apprendre, 60 pour tester ; lignes regroupées par recherche
app <- requete <= 240
dtrain <- lgb.Dataset(X[app, ], label = pertinence[app], group = rep(n_prod, 240))
parametres <- list(objective = "lambdarank", learning_rate = 0.05, num_leaves = 15, verbose = -1)
modele <- lgb.train(params = parametres, data = dtrain, nrounds = 200)
# NDCG@10 : qualité des 10 premiers résultats affichés (1 = ordre idéal)
dcg <- function(r) sum(r[1:10] / log2(2:11))
ndcg <- function(score) mean(sapply(split(seq_len(sum(!app)), requete[!app]), function(i)
dcg(pertinence[!app][i][order(-score[i])]) / dcg(sort(pertinence[!app][i], decreasing = TRUE))))
cat("NDCG@10 LambdaMART :", round(ndcg(predict(modele, X[!app, ])), 3), "\n")
cat("NDCG@10 tri par score texte :", round(ndcg(X[!app, "score_texte"]), 3), "\n")
print(lgb.importance(modele))
# Classement des résultats de recherche : Learning to Rank (LambdaMART) en Python
import numpy as np
import pandas as pd
from lightgbm import LGBMRanker
from sklearn.metrics import ndcg_score
# Simulation : 300 recherches, 20 produits candidats chacune
rng = np.random.default_rng(42)
n_req, n_prod = 300, 20
N = n_req * n_prod
X = pd.DataFrame({"score_texte": rng.random(N), "note_moyenne": rng.uniform(2.5, 5, N),
"ventes_30j": rng.poisson(20, N), "prix_relatif": rng.uniform(0.6, 1.6, N),
"en_stock": (rng.random(N) < 0.85).astype(int)})
latent = (2.5 * X.score_texte + 0.8 * (X.note_moyenne - 3.75) + 0.02 * X.ventes_30j
- (X.prix_relatif - 1) + 1.5 * X.en_stock + rng.normal(0, 0.5, N))
pertinence = np.digitize(latent, np.quantile(latent, [0.6, 0.8, 0.93])) # 0 = ignoré ... 3 = acheté
# 240 recherches pour apprendre, 60 pour tester ; lignes regroupées par recherche
app = np.arange(N) < 240 * n_prod
modele = LGBMRanker(objective="lambdarank", n_estimators=200, learning_rate=0.05, num_leaves=15, random_state=42, verbose=-1)
modele.fit(X[app], pertinence[app], group=[n_prod] * 240)
# NDCG@10 : qualité des 10 premiers résultats affichés (1 = ordre idéal)
vrai = pertinence[~app].reshape(60, n_prod)
print("NDCG@10 LambdaMART :", round(ndcg_score(vrai, modele.predict(X[~app]).reshape(60, n_prod), k=10), 3))
print("NDCG@10 tri par score texte :", round(ndcg_score(vrai, X.score_texte[~app].values.reshape(60, n_prod), k=10), 3))
print(pd.Series(modele.feature_importances_, index=X.columns).sort_values(ascending=False))
Le Normalized Discounted Cumulative Gain mesure la qualité d'un classement. Chaque résultat pertinent rapporte des points, d'autant moins qu'il est placé bas dans la liste. On divise par le score du classement idéal : 1 est parfait.
Pointwise prédit une note par produit, comme une régression. Pairwise apprend lequel de deux produits doit passer devant. Listwise optimise la qualité de la liste entière. LambdaMART travaille par paires, pondérées par leur effet sur le NDCG de la liste.
Par jugement humain sur un échantillon de recherches, ou à partir des comportements : un achat vaut plus qu'un ajout au panier, qui vaut plus qu'un clic. Les clics doivent être corrigés du biais de position, sinon le modèle apprend seulement à reproduire l'ordre actuel.
Le boosting qui fournit l'objectif lambdarank de l'exemple, rapide sur de gros volumes.
Voir la fiche → l'étage du dessusPrésélectionnent les candidats par proximité de sens avant que le learning to rank ne les ordonne.
Voir la fiche → une source de signauxSon score de goût peut devenir une variable du modèle de classement, à côté du prix et du stock.
Voir la fiche →Dataistudio forme les équipes au machine learning et à l'IA, sur des cas concrets.
Nous utilisons des cookies de mesure d'audience et de suivi publicitaire pour comprendre la fréquentation du site et l'efficacité de nos annonces. Rien n'est déposé sans votre accord. En savoir plus