Aprendizado de Ranqueamento

Aprendizado para Ranqueamento (Learning to Rank, LTR) é uma família de métodos de aprendizado de máquina (machine learning) projetada para ordenar itens (documentos, produtos, posts, vídeos) de modo que os itens mais relevantes apareçam primeiro. Diferentemente da classificação ou regressão padrão, o objetivo não é prever um rótulo absoluto por item, mas produzir uma ordenação de alta qualidade para cada contexto (uma consulta de busca, uma sessão de usuário, uma solicitação de recomendação).

LTR é amplamente usado em:

  • Mecanismos de busca (web, e-commerce, busca corporativa): ranquear documentos para uma consulta
  • Sistemas de recomendação: ranquear itens candidatos para um usuário (feed inicial, “para você”, “itens similares”)
  • Anúncios: ranquear anúncios por valor esperado sob restrições

Este artigo cobre a configuração central do problema, objetivos comuns de ranqueamento (pointwise/pairwise/listwise), avaliação—especialmente NDCG—e padrões práticos de uso em busca e recomendadores.

Que problema o Aprendizado para Ranqueamento resolve?

Na maioria das aplicações de ranqueamento, você tem um contexto e um conjunto de candidatos:

  • Busca: contexto = consulta q, candidatos = documentos d ∈ D(q)
  • Recomendadores: contexto = usuário (e possivelmente sessão) u, candidatos = itens i ∈ I(u)

O modelo produz um score para cada candidato, e o sistema ordena por esse score:

[ s(x_{c}) \rightarrow \text{sort candidates by } s \text{ descending} ]

onde (x_c) é a representação de atributos para um par contexto–candidato (por exemplo, atributos consulta–documento).

Duas propriedades-chave distinguem ranqueamento de “previsão” simples:

  1. Estrutura de grupos: exemplos vêm em grupos (por consulta/solicitação do usuário). O que importa é a ordenação relativa dentro de cada grupo.
  2. Utilidade concentrada no topo: erros nas posições 1–3 são muito mais custosos do que erros na posição 100.

Por causa dessas propriedades, o LTR usa objetivos e métricas especializadas que enfatizam a ordenação correta no topo da lista.

Configuração do problema e notação

Um conjunto de dados supervisionado comum para LTR se parece com:

  • Grupos (g = 1...G) (cada grupo é uma consulta ou solicitação)
  • Para o grupo (g), um conjunto de candidatos ({c_{g1}, ..., c_{gn_g}})
  • Atributos (x_{gi}) e um rótulo de relevância (y_{gi})

Os rótulos podem ser:

  • Binários: relevante vs não relevante (0/1)
  • Graduais: por exemplo, {0, 1, 2, 3} (não relevante → correspondência perfeita)
  • Implícitos: cliques, tempo de permanência, adicionar ao carrinho, compra (ruidosos e enviesados)

O modelo aprende uma função de pontuação (s_\theta(x)). No tempo de inferência (inference time), ele pontua cada candidato e ordena pelo score.

Objetivos de ranqueamento (funções de perda)

Objetivos de LTR tipicamente são categorizados em abordagens pontuais (pointwise), por pares (pairwise) e por lista (listwise). A escolha “certa” depende da qualidade dos rótulos, das restrições de computação e da métrica com a qual você se importa (frequentemente NDCG@k).

Objetivos pontuais

Métodos pontuais tratam ranqueamento como a previsão de um rótulo para cada item de forma independente.

Perdas pontuais comuns:

  • Regressão sobre relevância gradual: erro quadrático médio, Huber
  • Classificação sobre relevância binária: perda logística (entropia cruzada)

Exemplo (relevância binária):

[ \mathcal{L} = - y \log \sigma(s) - (1-y)\log(1-\sigma(s)) ]

Prós

  • Treinamento simples e estável
  • Funciona bem quando os rótulos de relevância têm alta qualidade e são calibrados
  • Fácil de implementar com modelos padrão (por exemplo, Regressão Linear/Logística (Linear/Logistic Regression), redes neurais)

Contras

  • Não otimiza diretamente a ordenação
  • Ignora o fato de que os itens competem dentro de uma solicitação de consulta/usuário
  • Muitas vezes é subótimo para métricas de ranqueamento top-k (top-k)

Objetivos pontuais são comuns para previsão de CTR (click-through rate, CTR) (prever probabilidade de clique), mas podem ficar desalinhados quando seu objetivo real é qualidade de ranqueamento.

Objetivos por pares

Métodos por pares aprendem a partir de comparações: para um determinado grupo, itens relevantes deveriam receber pontuações maiores do que itens menos relevantes.

Dado um par ((i, j)) onde (y_i > y_j), incentiva-se (s_i > s_j). Uma perda clássica (logística no estilo RankNet):

[ \mathcal{L}_{pair}(i,j) = \log\left(1 + e^{-(s_i - s_j)}\right) ]

Tipicamente você gera muitos pares de treinamento por grupo, frequentemente com amostragem para controlar o custo.

Prós

  • Otimiza diretamente a ordem relativa
  • Funciona bem com dados implícitos (clique > não clique, compra > clique, etc.)
  • Muitas vezes melhora o ranqueamento em comparação com a abordagem pontual

Contras

  • A geração de pares e a amostragem importam muito
  • Ainda não está diretamente atrelado ao NDCG@k; trata todas as inversões de forma semelhante, a menos que haja ponderação
  • Pode ser computacionalmente mais pesado do que a abordagem pontual para grupos grandes

Um aprimoramento prático é ponderar pares pelo quanto trocá-los mudaria a métrica-alvo, por exemplo, (\Delta)NDCG. Essa ideia leva ao LambdaRank/LambdaMART.

Objetivos por lista

Métodos por lista consideram a lista ranqueada inteira (ou um grande subconjunto) para cada grupo.

Abordagens por lista comuns:

  • ListNet / entropia cruzada softmax (softmax cross-entropy): tratam rótulos de relevância como uma distribuição sobre permutações ou posições
  • ListMLE: maximiza a verossimilhança da permutação ground-truth sob um modelo de Plackett–Luce
  • Gradientes alinhados à métrica (metric-aligned gradients) (LambdaRank/LambdaMART): computam “lambdas” que aproximam gradientes de NDCG e os aplicam a um modelo base (frequentemente árvores com boosting de gradiente)

LambdaRank e LambdaMART (amplamente usados na prática)

LambdaRank não define uma única perda escalar “limpa” em forma fechada. Em vez disso, define gradientes (“lambdas”) para pares de modo que:

  • O modelo aprende como um método por pares
  • Cada par é ponderado pela mudança no NDCG se os dois itens trocarem de posição

LambdaMART é LambdaRank aplicado a árvores de decisão com boosting (MART = Árvores de Regressão Aditiva Múltipla (Multiple Additive Regression Trees)), implementado em bibliotecas populares como LightGBM e XGBoost. Em muitos sistemas de ranqueamento em produção com atributos tabulares, LambdaMART é um baseline forte porque é robusto, rápido e preciso. Veja também Árvores de Decisão e Conjuntos.

Prós

  • Forte desempenho em objetivos do tipo NDCG@k
  • Frequentemente estado da arte para ranqueamento “clássico” baseado em atributos

Contras

  • O NDCG verdadeiro é não diferenciável; o treinamento é uma aproximação
  • O treinamento por lista pode ser mais complexo para modelos neurais e grandes conjuntos de candidatos

Escolhendo um objetivo na prática

Uma regra prática razoável:

  • Se você se importa com NDCG@k e tem relevância gradual (ou consegue derivá-la): LambdaMART ou uma abordagem por lista costuma ser excelente.
  • Se você tem principalmente feedback implícito (cliques, compras) e grande escala: abordagem por pares (ou por pares ponderada) é comum, às vezes combinada com desenviesamento.
  • Se você precisa de probabilidades (por exemplo, lances/anúncios): abordagem pontual pode ser apropriada, possivelmente seguida por uma etapa de ajuste fino ciente de ranqueamento.

Avaliação para ranqueamento: DCG e NDCG

Por que métricas de ranqueamento diferem de acurácia

Sistemas de ranqueamento são avaliados por:

  • Se os melhores itens aparecem no topo
  • Quão rápido o usuário consegue encontrar algo relevante

Então precisamos de métricas que:

  • Enfatizem o topo da lista
  • Lidem com relevância gradual
  • Comparem diferentes consultas de forma justa

DCG (Ganho Cumulativo com Desconto)

Para uma lista ranqueada até a posição (k), com rótulos de relevância (\text{rel}_i) na posição (i), uma forma comum é:

[ DCG@k = \sum_{i=1}^{k} \frac{2^{\text{rel}_i}-1}{\log_2(i+1)} ]

  • O ganho (2^{rel}-1) faz com que resultados altamente relevantes contem muito mais do que resultados marginalmente relevantes.
  • O desconto (\log_2(i+1)) penaliza colocar itens relevantes muito abaixo na lista.

NDCG (DCG Normalizado (Normalized DCG))

O DCG depende de quantos itens relevantes existem para uma consulta, então normalizamos pelo melhor DCG possível para aquela consulta (o ranqueamento “ideal”):

[ NDCG@k = \frac{DCG@k}{IDCG@k} ]

onde (IDCG@k) é o DCG@k da lista ordenada por relevância verdadeira decrescente.

O NDCG normalmente é calculado por consulta e então é feita a média entre as consultas.

Exemplo trabalhado (NDCG@5)

Suponha que, para uma consulta, você retorne 5 itens com relevância gradual:

Relevâncias da lista ranqueada: [3, 2, 0, 1, 0]

Calcule DCG@5:

  • posição 1: ((2^3-1)/\log_2(2) = 7/1 = 7)
  • posição 2: ((2^2-1)/\log_2(3) = 3/1.585 ≈ 1.892)
  • posição 3: ((2^0-1)/\log_2(4) = 0)
  • posição 4: ((2^1-1)/\log_2(5) = 1/2.322 ≈ 0.431)
  • posição 5: 0

Então (DCG@5 ≈ 7 + 1.892 + 0 + 0.431 + 0 = 9.323)

A ordenação ideal das relevâncias é [3, 2, 1, 0, 0]. Calcule (IDCG@5):

  • posição 1: 7
  • posição 2: 1.892
  • posição 3: ((2^1-1)/\log_2(4) = 1/2 = 0.5)
  • posições 4–5: 0

Então (IDCG@5 ≈ 9.392)

[ NDCG@5 \approx 9.323/9.392 = 0.9926 ]

Isso fica próximo de 1 porque o único erro é que o item com relevância 1 está na posição 4 em vez da posição 3, uma pequena penalidade no top-k.

Implementação de referência (Python)

import math

def dcg_at_k(rels, k):
    dcg = 0.0
    for i, rel in enumerate(rels[:k], start=1):
        gain = (2**rel - 1)
        discount = math.log2(i + 1)
        dcg += gain / discount
    return dcg

def ndcg_at_k(rels, k):
    dcg = dcg_at_k(rels, k)
    ideal = sorted(rels, reverse=True)
    idcg = dcg_at_k(ideal, k)
    return 0.0 if idcg == 0 else dcg / idcg

Variações comuns e ressalvas

  • A escolha de NDCG@k importa: otimize o que você realmente se importa (por exemplo, @10 para busca na web, @50 para tarefas com alta ênfase em recall).
  • Empates: rótulos graduais frequentemente criam empates; NDCG lida com isso naturalmente via IDCG.
  • Média: tipicamente calcula-se a média do NDCG por consulta (média macro (macro-average)) para que consultas frequentes não dominem, a menos que você intencionalmente pondere por tráfego.

Outras métricas de ranqueamento (brevemente)

  • MRR (Mean Reciprocal Rank): enfatiza a posição do primeiro item relevante; comum quando existe uma única “resposta correta”.
  • MAP (Mean Average Precision): boa para relevância binária e múltiplos itens relevantes.
  • Recall@k / Precision@k: úteis, mas menos sensíveis a relevância gradual e posições.

Dados de treino para LTR

Julgamentos explícitos

Julgamentos humanos de relevância (comuns em busca na web) fornecem rótulos graduais como 0–3 ou 0–4. Eles são de alta qualidade, mas caros, e podem ficar defasados em relação a conteúdo que muda rapidamente.

Feedback implícito (cliques, conversões) e viés

Recomendadores e muitos sistemas de busca dependem de sinais implícitos:

  • clique, tempo de permanência
  • adicionar ao carrinho, compra
  • curtidas, compartilhamentos, ocultações

Esses sinais são enviesados pelo ranqueamento atual do sistema:

  • Viés de posição: itens ranqueados mais alto recebem mais exposição e cliques independentemente da relevância.
  • Viés de seleção: você só observa feedback sobre itens exibidos.
  • Viés de confiança: usuários podem clicar nos primeiros resultados porque confiam no sistema.

Mitigações práticas incluem:

  • Buckets de randomização (pequenas fatias de tráfego com exploração)
  • Ponderação por propensão / métodos contrafactuais (LTR não enviesado)
  • Uso de múltiplos sinais (por exemplo, clique + permanência + conversão) em vez de somente cliques

Agrupamento por consulta/usuário e divisões de dados

Conjuntos de dados de LTR devem preservar o agrupamento:

  • Instâncias de treino são agrupadas por consulta/solicitação do usuário
  • As divisões devem evitar vazamento:
    • divisões baseadas em tempo para catálogos em evolução
    • divisões por consulta para evitar vazamento de quase duplicatas
    • divisões por usuário em recomendadores para medir generalização

Famílias de modelos para Aprendizado para Ranqueamento

Modelos lineares e simples

Um pontuador linear (s = w^\top x) pode ser surpreendentemente forte com bons atributos. É rápido e interpretável, mas pode carecer de interações não lineares.

Árvores de decisão com boosting de gradiente (gradient-boosted decision trees, GBDT): um cavalo de batalha

Ranqueadores baseados em GBDT (especialmente LambdaMART) são amplamente usados para ranqueamento rico em atributos:

  • lidam bem com tipos de atributos mistos
  • capturam interações não lineares entre atributos
  • forte desempenho “out-of-the-box”

Eles são particularmente eficazes em pipelines “tradicionais” de LTR, em que você tem atributos engenheirados (score BM25, popularidade, recência, atributos de intenção de consulta, etc.).

Ranqueadores neurais

Abordagens neurais são comuns quando texto, imagens ou incorporações (embeddings) importam:

  • Modelos de duas torres (two-tower models) (bi-codificador (bi-encoder)): codificam consulta e documento/item separadamente; rápidos para recuperação e busca aproximada de vizinhos mais próximos (approximate nearest neighbor search); intimamente relacionados a Aprendizado Métrico (Metric Learning).
  • Codificadores cruzados (cross-encoders): codificam conjuntamente consulta + documento usando atenção (attention) (frequentemente via Arquitetura Transformer (Transformer Architecture)); maior acurácia, mas caros—comumente usados para re-ranqueamento (reranking) de um pequeno conjunto de candidatos.
  • Objetivos de treino podem ser pontuais (entropia cruzada), por pares (contrastiva (contrastive)) ou aproximações por lista.

Em muitos sistemas reais, modelos neurais alimentam a geração de candidatos e/ou o re-ranqueamento, às vezes combinados com GBDT ou modelos lineares.

Uso prático em busca: recuperação + re-ranqueamento

A maioria das pilhas de busca em produção usa múltiplas etapas:

  1. Geração de candidatos (candidate generation): recuperar algumas centenas a alguns milhares de candidatos rapidamente (índice invertido, BM25, recuperação por incorporação).
  2. Cálculo de atributos: computar atributos ricos para cada candidato (correspondência de texto, popularidade, personalização, recência).
  3. Re-ranqueador de aprendizado para ranqueamento: aplicar um modelo de LTR para ordenar candidatos.
  4. Pós-processamento: filtragem, deduplicação, regras de negócio, restrições de diversidade.

Exemplo: re-ranqueamento de busca em e-commerce

Contexto: usuário busca “tênis de corrida”.

Candidatos: 1000 produtos recuperados via correspondência lexical.

Atributos podem incluir:

  • Relevância de texto: BM25, match de título, match de marca
  • Atributos de preço: distância em relação ao gasto típico do usuário
  • Popularidade: ranking de vendas, CTR
  • Estoque: disponível, velocidade de entrega
  • Personalização: similaridade com compras anteriores do usuário
  • Recência: impulso para novos lançamentos

Rótulos podem ser:

  • Julgamentos explícitos de avaliadores de relevância
  • Implícitos: compra (maior), adicionar ao carrinho, clique longo, clique curto, sem clique

Uma abordagem comum:

  • Treinar um modelo LambdaMART para otimizar NDCG@10 usando rótulos graduais derivados de ações do usuário.
  • Validar offline com NDCG@10 e também monitorar métricas de negócio (conversão, receita) online via testes A/B (A/B tests).

Exemplo mínimo de ranqueamento com LightGBM

import lightgbm as lgb
import numpy as np

# X: feature matrix (N x d)
# y: relevance labels (N,)
# group: sizes per query (e.g., [n_q1, n_q2, ...])
train_data = lgb.Dataset(X_train, label=y_train, group=group_train)
valid_data = lgb.Dataset(X_valid, label=y_valid, group=group_valid)

params = {
    "objective": "lambdarank",
    "metric": "ndcg",
    "ndcg_eval_at": [10],
    "learning_rate": 0.05,
    "num_leaves": 63,
    "min_data_in_leaf": 20,
}

model = lgb.train(
    params,
    train_data,
    valid_sets=[valid_data],
    num_boost_round=2000,
    callbacks=[lgb.early_stopping(stopping_rounds=50)]
)

scores = model.predict(X_test)
# Sort candidates within each query by score descending.

Detalhe-chave: o array group é essencial—sem ele, o modelo não saberá quais itens competem entre si.

Uso prático em sistemas de recomendação

Em recomendadores, o ranqueamento tipicamente acontece após a geração de candidatos:

  1. Geração de candidatos: filtragem colaborativa, recuperação item-para-item, recuperação por incorporação de duas torres, etc. (veja Sistemas de Recomendação (Recommender Systems))
  2. Ranqueamento: pontuar e ordenar candidatos para um usuário/sessão
  3. Re-ranqueamento: aplicar restrições (diversidade, novidade, regras de negócio)

Como é o “rótulo” em recomendadores?

Frequentemente você otimiza um alvo proxy:

  • clique / assistir / permanência
  • adicionar ao carrinho / compra
  • engajamento de longo prazo

Os rótulos podem ser implícitos e esparsos. Objetivos por pares são comuns:

  • Para um usuário, tratar itens com interação como positivos e itens amostrados como negativos.
  • Aprender a pontuar positivos acima de negativos.

No entanto, muitos recomendadores precisam de qualidade top-k ao longo de múltiplos itens relevantes. Objetivos por lista (ou por pares ponderados por NDCG) podem ajudar, especialmente quando você consegue atribuir rótulos graduais como:

  • compra = 3
  • adicionar ao carrinho = 2
  • clique = 1
  • impressão/sem ação = 0

Exemplo prático: ranqueamento de “feed inicial”

Candidatos: 500 posts de criadores seguidos + pool de tendências.

Atributos:

  • CTR previsto, tempo de permanência previsto
  • atributos de afinidade com o criador
  • recência
  • similaridade de incorporações de conteúdo

Treinamento:

  • Usar um objetivo de ranqueamento alinhado com NDCG@k onde os rótulos refletem valor de engajamento.
  • Avaliar offline com NDCG@k e métricas de calibração (se você também precisar de probabilidades).

Implantação:

  • Monitorar métricas online e também limites de segurança (guardrails) (taxa de spam, diversidade, justiça para criadores).

Armadilhas comuns e dicas práticas

  • Otimizar o k errado: se a UI mostra 5 itens, NDCG@100 pode não correlacionar com resultados do usuário. Alinhe treino/avaliação com a realidade do produto (por exemplo, NDCG@5 ou @10).
  • Vazamento via atributos: atributos como “CTR histórico” calculados usando dados futuros podem vazar silenciosamente. Use pipelines de atributos corretos no tempo.
  • Rótulos e métrica desalinhados: se os rótulos refletem cliques mas você otimiza receita, talvez você precise de rótulos graduais ou alvos multi-tarefa (multi-task).
  • Ignorar viés em dados implícitos: um modelo treinado em cliques enviesados pode reforçar viés de exposição (“os ricos ficam mais ricos”). Use exploração e desenviesamento quando possível.
  • Overfitting em consultas/usuários frequentes: garanta que divisões e ponderações reflitam seus objetivos (média macro vs ponderada por tráfego).
  • Esquecer o pós-processamento: sistemas reais aplicam restrições (estoque, política, diversidade). Avalie o pipeline completo, não apenas o ranqueador bruto.

Tópicos avançados (visão geral breve)

  • LTR não enviesado / contrafactual (counterfactual): corrige viés de posição usando escores de propensão; depende de políticas de logging randomizadas.
  • Ordenação e top-k diferenciáveis (differentiable sorting and top-k): aproximações neurais (por exemplo, ordenação suave) que miram mais diretamente métricas por lista, geralmente em pesquisa ou aplicações especializadas.
  • Ranqueamento multiobjetivo (multi-objective ranking): combina relevância com restrições (diversidade, justiça, segurança). Frequentemente implementado como re-ranqueamento ou otimização com restrições por cima de um pontuador de LTR.
  • Destilação e re-ranqueamento com LLM (LLM-based reranking): modelos grandes podem servir como re-ranqueadores poderosos, às vezes destilados em ranqueadores menores para latência. Quando usados, ainda dependem de conceitos de LTR: conjuntos de candidatos, perdas de ranqueamento e avaliação no estilo NDCG.

Resumo

Aprendizado para Ranqueamento foca em produzir a melhor ordenação de itens para cada solicitação de consulta/usuário, enfatizando correção no topo da lista. Os principais ingredientes são:

  • Objetivos:
    • pontuais (simples, mas menos alinhados a ranqueamento),
    • por pares (aprendem preferências),
    • por lista (melhor alinhamento com métricas de ranqueamento; LambdaMART é uma escolha clássica e forte).
  • Avaliação: NDCG@k é uma métrica padrão porque suporta relevância gradual e importância concentrada no topo.
  • Aplicações: LTR é central para busca e recomendadores modernos, geralmente como uma etapa de re-ranqueamento sobre um conjunto de candidatos.

Para muitos sistemas práticos, um baseline forte é: geração de candidatos + re-ranqueamento com LambdaMART avaliado com NDCG@k, e então melhorar iterativamente com melhores atributos, rótulos implícitos desenviesados e experimentação online.