Skip to content
このページはまだお使いの言語に翻訳されていません。英語版を表示しています。

Best-Worst Scaling

Annotazione comparativa efficiente con Best-Worst Scaling, generazione automatica di tuple e calcolo dei punteggi.

Best-Worst Scaling

Novità nella v2.3.0

Il Best-Worst Scaling (BWS), noto anche come Maximum Difference Scaling (MaxDiff), è un metodo di annotazione comparativa in cui agli annotatori viene mostrata una tupla di elementi (in genere 4) e viene chiesto di selezionare l'elemento migliore e il peggiore secondo un determinato criterio. Il BWS produce punteggi scalari affidabili a partire da semplici giudizi binari, richiedendo molte meno annotazioni rispetto alle scale di valutazione dirette per ottenere la stessa potenza statistica.

Il BWS è particolarmente utile quando:

  • Le valutazioni numeriche dirette risentono del bias dell'annotatore (l'utilizzo della scala varia tra le persone)
  • È necessaria una classifica affidabile di centinaia o migliaia di elementi
  • La dimensione della qualità è intrinsecamente relativa (ad es., "quale traduzione è più scorrevole?")
  • Si vuole massimizzare le informazioni per annotazione (ogni giudizio BWS fornisce più bit rispetto a una valutazione Likert)

Configurazione di base

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 dei dati

Ogni istanza nel file di dati deve contenere un elenco di elementi da confrontare. Potato genera le tuple da questo elenco automaticamente.

Opzione 1: tutti gli elementi in un'unica istanza

Se si dispone di un singolo insieme di elementi da classificare (ad es., traduzioni di una 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."}
  ]
}

Opzione 2: tuple pre-generate

Se si desidera il controllo completo su quali elementi appaiono insieme, fornire tuple pre-generate:

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."}
  ]
}

Generazione automatica di tuple

Quando l'elenco degli elementi è più lungo della dimensione della tupla, Potato genera automaticamente le tuple. L'algoritmo di generazione garantisce:

  • Ogni elemento appare approssimativamente nello stesso numero di tuple
  • Ogni coppia di elementi co-occorre in almeno una tupla (per un punteggio relativo affidabile)
  • Le tuple sono bilanciate in modo che nessun elemento sia sempre mostrato per primo o per ultimo

Configura la generazione di tuple:

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

Per un insieme di N elementi con dimensione della tupla T e tuples_per_item = K, Potato genera approssimativamente N * K / T tuple totali.

Metodi di generazione

balanced_incomplete (predefinito): Utilizza un disegno a blocchi incompleto bilanciato per massimizzare l'efficienza statistica. Ogni elemento appare ugualmente spesso e la co-occorrenza delle coppie è il più uniforme possibile. Consigliato per la maggior parte dei casi d'uso.

random: Campiona casualmente le tuple con sostituzione. Più veloce per set di elementi molto grandi (N > 10.000) ma statisticamente meno efficiente. Da usare quando il bilanciamento esatto non è critico.

Pre-generazione di tuple tramite CLI

Per progetti su larga scala, genera le tuple in anticipo:

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

Metodi di punteggio

Dopo l'annotazione, Potato calcola i punteggi degli elementi dai giudizi BWS utilizzando tre metodi.

1. Conteggio (predefinito)

Il metodo più semplice. Il punteggio di ogni elemento è la proporzione di volte in cui è stato selezionato come "migliore" meno la proporzione di volte in cui è stato selezionato come "peggiore":

Punteggio(elemento) = (conteggio_migliore - conteggio_peggiore) / totale_apparizioni

I punteggi variano da -1,0 (sempre peggiore) a +1,0 (sempre migliore).

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

2. Bradley-Terry

Adatta un modello Bradley-Terry ai confronti a coppie impliciti dai giudizi BWS. Ogni selezione "migliore" implica che l'elemento migliore è preferito a tutti gli altri elementi nella tupla; ogni selezione "peggiore" implica che tutti gli altri elementi sono preferiti al peggiore.

Bradley-Terry produce punteggi su una scala log-odds con migliori proprietà statistiche rispetto al conteggio, specialmente con dati sparsi.

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

3. Plackett-Luce

Una generalizzazione di Bradley-Terry che modella la classifica completa implicita da ogni giudizio di tupla (migliore > elementi medi > peggiore). Plackett-Luce estrae più informazioni da ogni annotazione rispetto a Bradley-Terry.

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

Confronto dei metodi di punteggio

MetodoVelocitàEfficienza dei datiGestisce dati sparsiModello statistico
ConteggioVeloceBassaNessuno (descrittivo)
Bradley-TerryMedioMediaModerataConfronto a coppie
Plackett-LucePiù lentoAltaModerataClassifica completa

Per la maggior parte dei progetti, Bradley-Terry è il miglior predefinito. Usa il Conteggio per un'analisi esplorativa rapida e Plackett-Luce quando hai bisogno della massima efficienza statistica da annotazioni limitate.

Configurazione del punteggio in YAML

È anche possibile configurare il punteggio direttamente nella configurazione del progetto per il calcolo automatico:

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

Integrazione con il pannello di amministrazione

Il pannello di amministrazione include una scheda BWS dedicata che mostra:

  • Distribuzione dei punteggi: Istogramma dei punteggi attuali degli elementi
  • Avanzamento delle annotazioni: Quante tuple sono state annotate rispetto al totale
  • Copertura per elemento: Quante volte ogni elemento è stato visualizzato
  • Coerenza tra annotatori: Affidabilità split-half dei punteggi BWS
  • Convergenza dei punteggi: Grafico a linee che mostra come i punteggi si stabilizzano man mano che vengono raccolte più annotazioni

Accedi alle analisi BWS dalla riga di 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

Dimensioni BWS multiple

È possibile eseguire più schemi BWS sullo stesso insieme di elementi per valutare diverse dimensioni di qualità:

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"

Entrambi gli schemi condividono le stesse tuple (Potato genera un set di tuple per ogni items_key), quindi gli annotatori vedono ogni tupla una volta ma forniscono due giudizi.

Formato di output

Le annotazioni BWS vengono salvate per 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"
}

Esempio completo

Configurazione completa per la valutazione di sistemi di traduzione automatica:

yaml
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/"
output_annotation_format: "jsonl"

Ulteriori letture

Per i dettagli di implementazione, consulta la documentazione sorgente.