Skip to content

Best-Worst Scaling

Anotação comparativa eficiente com Best-Worst Scaling no Potato — gera automaticamente tuplas de comparação e converte as seleções em pontuações contínuas de qualidade.

Novo na v2.3.0

Best-Worst Scaling (BWS), também conhecido como Maximum Difference Scaling (MaxDiff), é um método de anotação comparativa em que os anotadores veem uma tupla de itens (normalmente 4) e devem selecionar o item melhor e o pior segundo algum critério. O BWS produz pontuações escalares confiáveis a partir de simples julgamentos binários, exigindo muito menos anotações do que as escalas de avaliação direta para atingir o mesmo poder estatístico.

O BWS é especialmente útil quando:

  • As avaliações numéricas diretas sofrem com o viés do anotador (o uso da escala varia entre as pessoas)
  • Você precisa de um ranking confiável de centenas ou milhares de itens
  • A dimensão de qualidade é inerentemente relativa (por exemplo, "qual tradução é a mais fluente?")
  • Você quer maximizar a informação por anotação (cada julgamento de BWS fornece mais bits do que uma avaliação Likert)

Interface de anotação de best-worst scalingInterface de best-worst scaling para anotação comparativa no Potato

Configuração Básica

yaml
annotation_schemes:
  - annotation_type: best_worst_scaling
    name: fluency
    description: "Select the BEST and WORST translation by fluency"
 
    # Items to compare
    items_key: "translations"    # key in instance data containing the list of items
 
    # Tuple size (how many items shown at once)
    tuple_size: 4                # typically 4; valid range is 3-8
 
    # Labels for best/worst buttons
    best_label: "Most Fluent"
    worst_label: "Least Fluent"
 
    # Display options
    show_item_labels: true       # show "A", "B", "C", "D" labels
    randomize_order: true        # randomize item order within each tuple
    show_source: false           # optionally show which system produced each item
 
    # Validation
    label_requirement:
      required: true             # must select both best and worst

Formato dos Dados

Cada instância no seu arquivo de dados deve conter uma lista de itens a comparar. O Potato gera tuplas dessa lista automaticamente.

Opção 1: Todos os Itens em Uma Instância

Se você tem um único conjunto de itens para ranquear (por exemplo, traduções de uma frase):

json
{
  "id": "sent_001",
  "source": "The cat sat on the mat.",
  "translations": [
    {"id": "sys_a", "text": "Le chat s'est assis sur le tapis."},
    {"id": "sys_b", "text": "Le chat a assis sur le tapis."},
    {"id": "sys_c", "text": "Le chat etait assis sur le mat."},
    {"id": "sys_d", "text": "Le chat se tenait sur le tapis."}
  ]
}

Opção 2: Tuplas Pré-Geradas

Se você quiser controle total sobre quais itens aparecem juntos, forneça tuplas pré-geradas:

json
{
  "id": "tuple_001",
  "translations": [
    {"id": "sys_a", "text": "Le chat s'est assis sur le tapis."},
    {"id": "sys_b", "text": "Le chat a assis sur le tapis."},
    {"id": "sys_c", "text": "Le chat etait assis sur le mat."},
    {"id": "sys_d", "text": "Le chat se tenait sur le tapis."}
  ]
}

Geração Automática de Tuplas

Quando sua lista de itens é maior do que o tamanho da tupla, o Potato gera tuplas automaticamente. O algoritmo de geração garante que:

  • Todo item apareça em aproximadamente o mesmo número de tuplas
  • Todo par de itens coocorra em pelo menos uma tupla (para uma pontuação relativa confiável)
  • As tuplas sejam balanceadas, de modo que nenhum item seja sempre mostrado primeiro ou por último

Configure a geração de tuplas:

yaml
annotation_schemes:
  - annotation_type: best_worst_scaling
    name: fluency
    items_key: "translations"
    tuple_size: 4
 
    tuple_generation:
      method: balanced_incomplete  # balanced_incomplete or random
      tuples_per_item: 5           # each item appears in ~5 tuples
      seed: 42                     # for reproducibility
      ensure_pair_coverage: true   # every pair co-occurs at least once

Para um conjunto de N itens com tamanho de tupla T e tuples_per_item = K, o Potato gera aproximadamente N * K / T tuplas no total.

Métodos de Geração

balanced_incomplete (padrão): Usa um delineamento de blocos incompletos balanceados para maximizar a eficiência estatística. Todo item aparece com a mesma frequência, e a coocorrência de pares é a mais uniforme possível. Recomendado para a maioria dos casos de uso.

random: Amostra tuplas aleatoriamente com reposição. Mais rápido para conjuntos de itens muito grandes (N > 10.000), mas estatisticamente menos eficiente. Use quando o balanceamento exato não for crítico.

Pré-Gerando Tuplas via CLI

Para projetos de grande escala, gere as tuplas com antecedência:

bash
python -m potato.bws generate-tuples \
  --items data/items.jsonl \
  --tuple-size 4 \
  --tuples-per-item 5 \
  --output data/tuples.jsonl \
  --seed 42

Métodos de Pontuação

Após a anotação, o Potato calcula as pontuações dos itens a partir dos julgamentos de BWS usando três métodos.

1. Contagem (Padrão)

O método mais simples. A pontuação de cada item é a proporção de vezes que foi selecionado como "melhor" menos a proporção de vezes que foi selecionado como "pior":

Pontuação(item) = (best_count - worst_count) / total_appearances

As pontuações variam de -1,0 (sempre pior) a +1,0 (sempre melhor).

bash
python -m potato.bws score \
  --config config.yaml \
  --method counting \
  --output scores.csv

2. Bradley-Terry

Ajusta um modelo de Bradley-Terry às comparações pareadas implícitas nos julgamentos de BWS. Cada seleção de "melhor" implica que o melhor item é preferido a todos os demais itens da tupla; cada seleção de "pior" implica que todos os demais itens são preferidos ao pior.

O Bradley-Terry produz pontuações em escala log-odds com propriedades estatísticas melhores do que a contagem, especialmente com dados esparsos.

bash
python -m potato.bws score \
  --config config.yaml \
  --method bradley_terry \
  --max-iter 1000 \
  --tolerance 1e-6 \
  --output scores.csv

3. Plackett-Luce

Uma generalização do Bradley-Terry que modela o ranking completo implícito em cada julgamento de tupla (melhor > itens intermediários > pior). O Plackett-Luce extrai mais informação de cada anotação do que o Bradley-Terry.

bash
python -m potato.bws score \
  --config config.yaml \
  --method plackett_luce \
  --output scores.csv

Comparando os Métodos de Pontuação

MétodoVelocidadeEficiência de DadosLida com Dados EsparsosModelo Estatístico
ContagemRápidoBaixaSimNenhum (descritivo)
Bradley-TerryMédioMédiaModeradoComparação pareada
Plackett-LuceMais lentoAltaModeradoRanking completo

Para a maioria dos projetos, Bradley-Terry é o melhor padrão. Use Contagem para análise exploratória rápida e Plackett-Luce quando precisar de máxima eficiência estatística a partir de anotações limitadas.

Configuração de Pontuação no YAML

Você também pode configurar a pontuação diretamente na configuração do projeto para cálculo automático:

yaml
annotation_schemes:
  - annotation_type: best_worst_scaling
    name: fluency
    items_key: "translations"
    tuple_size: 4
 
    scoring:
      method: bradley_terry
      auto_compute: true           # compute scores after each annotation session
      output_file: "output/fluency_scores.csv"
      include_confidence: true     # include confidence intervals
      bootstrap_iterations: 1000   # for confidence interval estimation

Integração com o Painel de Administração

O painel de administração inclui uma aba dedicada ao BWS que mostra:

  • Distribuição de pontuações: Histograma das pontuações atuais dos itens
  • Progresso da anotação: Quantas tuplas foram anotadas em relação ao total
  • Cobertura por item: Quantas vezes cada item foi visto
  • Consistência entre anotadores: Confiabilidade por divisão pela metade (split-half) das pontuações de BWS
  • Convergência das pontuações: Gráfico de linha mostrando como as pontuações se estabilizam à medida que mais anotações são coletadas

Acesse a análise de BWS pela linha de comando:

bash
python -m potato.bws stats --config config.yaml
text
BWS Statistics
==============
Schema: fluency
Items: 200
Tuples: 250 (annotated: 180 / 250)
Annotations: 540 (3 annotators)

Score Summary (Bradley-Terry):
  Mean:   0.02
  Std:    0.43
  Range: -0.91 to +0.87

Top 5 Items:
  sys_d:  0.87 (±0.08)
  sys_a:  0.72 (±0.09)
  sys_f:  0.65 (±0.10)
  sys_b:  0.51 (±0.11)
  sys_k:  0.48 (±0.09)

Split-Half Reliability: r = 0.94

Múltiplas Dimensões de BWS

Você pode executar vários esquemas de BWS sobre o mesmo conjunto de itens para avaliar diferentes dimensões de qualidade:

yaml
annotation_schemes:
  - annotation_type: best_worst_scaling
    name: fluency
    description: "Select BEST and WORST by fluency"
    items_key: "translations"
    tuple_size: 4
    best_label: "Most Fluent"
    worst_label: "Least Fluent"
 
  - annotation_type: best_worst_scaling
    name: adequacy
    description: "Select BEST and WORST by meaning preservation"
    items_key: "translations"
    tuple_size: 4
    best_label: "Most Accurate"
    worst_label: "Least Accurate"

Ambos os esquemas compartilham as mesmas tuplas (o Potato gera um conjunto de tuplas por items_key), então os anotadores veem cada tupla uma vez, mas fornecem dois julgamentos.

Formato de Saída

As anotações de BWS são salvas por tupla:

json
{
  "id": "tuple_001",
  "annotations": {
    "fluency": {
      "best": "sys_d",
      "worst": "sys_c"
    },
    "adequacy": {
      "best": "sys_a",
      "worst": "sys_c"
    }
  },
  "annotator": "user_1",
  "timestamp": "2026-03-01T14:22:00Z"
}

Exemplo Completo

Configuração completa para avaliar sistemas de tradução automática:

yaml
annotation_task_name: "MT System Ranking (BWS)"
task_dir: "."
 
data_files:
  - "data/mt_tuples.jsonl"
 
item_properties:
  id_key: id
  text_key: source
 
instance_display:
  fields:
    - key: source
      type: text
      display_options:
        label: "Source Sentence"
 
annotation_schemes:
  - annotation_type: best_worst_scaling
    name: overall_quality
    description: "Select the BEST and WORST translation"
    items_key: "translations"
    tuple_size: 4
    best_label: "Best Translation"
    worst_label: "Worst Translation"
    randomize_order: true
    show_item_labels: true
 
    tuple_generation:
      method: balanced_incomplete
      tuples_per_item: 5
      seed: 42
 
    scoring:
      method: bradley_terry
      auto_compute: true
      output_file: "output/quality_scores.csv"
      include_confidence: true
 
output_annotation_dir: "output/"
export_annotation_format: "jsonl"

Leitura Adicional

Para detalhes de implementação, consulte a documentação de origem.