Skip to content
Guides8 min read

Controllo qualità per l'annotazione in crowdsourcing

Buone pratiche per tenere alta la qualità nei progetti di annotazione, con strategie concrete da mettere in pratica dentro e fuori Potato.

Potato Team

Il controllo qualità è quello che separa le annotazioni utili dal rumore. Questa guida raccoglie le strategie che reggono alla prova dei fatti, sia nei progetti in crowdsourcing sia in quelli interni. Per le funzioni su cui si appoggiano, vedi la documentazione sul controllo qualità.

Il controllo qualità lungo la durata del progetto: verifiche prima, durante e dopo l'annotazioneIl controllo qualità lungo la durata del progetto

Il quadro d'insieme

Nessuna verifica basta da sola, quindi quasi tutti i progetti ne sovrappongono alcune:

  1. Verifiche di attenzione: controllano che gli annotatori stiano davvero seguendo il task
  2. Ridondanza: raccogliere più annotazioni per ogni elemento
  3. Metriche di accordo: misurano la coerenza tra annotatori
  4. Formazione e linee guida: servono a far capire il task
  5. Revisione manuale: campionare le annotazioni e controllarne la qualità

Verifiche di attenzione con surveyflow

Potato offre verifiche di attenzione di base attraverso il sistema surveyflow. Puoi inserire pagine di questionario tra un blocco di annotazione e l'altro, in cui si chiede all'annotatore di confermare che sta prestando attenzione.

yaml
annotation_task_name: "Sentiment Annotation with Checks"
 
surveyflow:
  on: true
  order:
    - survey_instructions
    - annotation
    - survey_attention_check
    - annotation
    - survey_completion

Le domande di verifica si definiscono come una pagina di questionario:

yaml
# In your surveyflow survey definitions
survey_attention_check:
  - question: "To confirm you're paying attention, please select 'Strongly Agree'."
    type: radio
    options:
      - Strongly Disagree
      - Disagree
      - Neutral
      - Agree
      - Strongly Agree

Il supporto integrato di Potato per le verifiche di attenzione è limitato. Se vuoi rilevare automaticamente chi non le supera, escludere annotatori e cose simili, ti servono script di post-elaborazione oppure le funzioni di qualità della tua piattaforma di crowdsourcing.

Ridondanza: più annotazioni per elemento

Raccogliere più annotazioni per ogni elemento è uno dei metodi di controllo qualità più affidabili. Si configura nella parte dati:

yaml
annotation_task_name: "Multi-Annotator Sentiment Task"
 
data_files:
  - path: data.json
    list_as_text: false
    sampling: random
 
# Control how many annotators see each item through assignment logic
# This is typically managed through your annotator assignment system

Su piattaforme di crowdsourcing come Prolific puoi:

  • Pubblicare più volte la stessa HIT per ottenere annotazioni ridondanti
  • Usare gruppi di worker diversi sugli stessi dati
  • Scrivere una logica di assegnazione su misura nella tua pipeline di dati

Misurare l'accordo tra annotatori

L'accordo lo calcola Potato per te. Imposta agreement_metrics: enabled: true e l'alpha di Krippendorff compare nella dashboard di amministrazione man mano che arrivano le annotazioni. Il codice qui sotto conviene comunque conoscerlo, per quando ti serve una metrica che Potato non riporta o quando stai analizzando un dataset già esportato:

Kappa di Cohen (due annotatori)

Per annotazioni categoriali con due annotatori:

python
from sklearn.metrics import cohen_kappa_score
 
# After collecting annotations
annotator1_labels = ["Positive", "Negative", "Positive", ...]
annotator2_labels = ["Positive", "Negative", "Neutral", ...]
 
kappa = cohen_kappa_score(annotator1_labels, annotator2_labels)
print(f"Cohen's Kappa: {kappa:.3f}")

Kappa di Fleiss (più annotatori)

Con tre o più annotatori:

python
from statsmodels.stats.inter_rater import fleiss_kappa
import numpy as np
 
# Build a matrix of label counts per item
# Each row is an item, each column is a label category
ratings_matrix = np.array([
    [3, 0, 0],  # Item 1: 3 Positive, 0 Negative, 0 Neutral
    [2, 1, 0],  # Item 2: 2 Positive, 1 Negative, 0 Neutral
    [0, 0, 3],  # Item 3: 0 Positive, 0 Negative, 3 Neutral
    ...
])
 
kappa = fleiss_kappa(ratings_matrix)
print(f"Fleiss' Kappa: {kappa:.3f}")

Come leggere i valori

Valore di kappaInterpretazione
< 0.20Accordo scarso
0.21 - 0.40Accordo discreto
0.41 - 0.60Accordo moderato
0.61 - 0.80Accordo sostanziale
0.81 - 1.00Accordo quasi perfetto

Potato mette a disposizione verifiche di attenzione, elementi gold e il monitoraggio dell'accordo tra annotatori per tenere sotto controllo la qualità:

Controllo qualità con scala Likert in Potato

Elementi gold standard

Gli elementi gold standard sono elementi già etichettati, di cui conosci la risposta corretta, che mescoli ai tuoi dati. Servono a individuare chi tira a indovinare o non sta prestando attenzione.

Creare gli elementi gold

  1. Prepara un insieme di elementi con risposte corrette chiare e non ambigue
  2. Falli etichettare da esperti
  3. Mescolali ai dati di annotazione ordinari
json
[
  {
    "id": "gold_001",
    "text": "I absolutely love this product! Best purchase ever!",
    "is_gold": true,
    "gold_label": "Positive"
  },
  {
    "id": "gold_002",
    "text": "This is terrible. Complete waste of money. Worst experience.",
    "is_gold": true,
    "gold_label": "Negative"
  },
  {
    "id": "regular_001",
    "text": "The product arrived on time and works as expected.",
    "is_gold": false
  }
]

Analizzare i risultati sugli elementi gold

Dopo la raccolta, guarda come se l'è cavata ciascun annotatore sugli elementi gold:

python
import json
 
def calculate_gold_accuracy(annotations_file, gold_labels):
    with open(annotations_file) as f:
        annotations = json.load(f)
 
    annotator_scores = {}
 
    for item_id, item_annotations in annotations.items():
        if item_id in gold_labels:
            expected = gold_labels[item_id]
            for annotator, label in item_annotations.items():
                if annotator not in annotator_scores:
                    annotator_scores[annotator] = {'correct': 0, 'total': 0}
                annotator_scores[annotator]['total'] += 1
                if label == expected:
                    annotator_scores[annotator]['correct'] += 1
 
    for annotator, scores in annotator_scores.items():
        accuracy = scores['correct'] / scores['total']
        print(f"{annotator}: {accuracy:.1%} gold accuracy")
 
    return annotator_scores

Indicatori di qualità basati sul tempo

Potato registra i tempi di annotazione nei file di output. Usa questi dati per segnalare le annotazioni potenzialmente scadenti:

Analizzare i tempi

python
import json
from statistics import mean, stdev
 
def analyze_timing(annotations_file):
    with open(annotations_file) as f:
        data = json.load(f)
 
    times = []
    for item in data.values():
        if 'time_spent' in item:
            times.append(item['time_spent'])
 
    avg_time = mean(times)
    std_time = stdev(times)
 
    # Flag annotations that are too fast (< 2 std below mean)
    threshold = max(avg_time - 2 * std_time, 2)  # At least 2 seconds
 
    flagged = [t for t in times if t < threshold]
    print(f"Average time: {avg_time:.1f}s")
    print(f"Flagged as too fast: {len(flagged)} items")

Controllo qualità a livello di piattaforma

Se lavori su piattaforme di crowdsourcing, sfrutta le loro funzioni di qualità:

Prolific

  • Usa i filtri di preselezione (tasso di approvazione, studi precedenti)
  • Richiedi un tempo minimo di completamento
  • Inserisci domande di verifica dell'attenzione nel questionario iniziale
  • Controlla le consegne prima di approvare il pagamento

MTurk

  • Richiedi un tasso minimo di approvazione delle HIT (>95%)
  • Usa i test di qualificazione
  • Imposta approvazione e rifiuto automatici in base a criteri
  • Blocca i worker che non superano i controlli di qualità

Controlli di qualità in post-elaborazione

Automatizza qualche verifica sui dati raccolti:

python
def quality_check_annotations(annotations_file):
    with open(annotations_file) as f:
        data = json.load(f)
 
    issues = []
 
    for annotator_id, items in group_by_annotator(data).items():
        labels = [item['label'] for item in items]
 
        # Check for single-label bias (always selecting same option)
        unique_labels = set(labels)
        if len(unique_labels) == 1 and len(labels) > 10:
            issues.append(f"{annotator_id}: Only used label '{labels[0]}'")
 
        # Check for position bias (always selecting first option)
        # Requires knowing option order in your schema
 
        # Check for very fast submissions
        times = [item.get('time_spent', 0) for item in items]
        avg_time = sum(times) / len(times) if times else 0
        if avg_time < 3:
            issues.append(f"{annotator_id}: Average time only {avg_time:.1f}s")
 
    return issues

Buone pratiche

Fai partire gli annotatori dalla fase di formazione di Potato, prima che tocchino dati veri. Scrivi linee guida chiare: quelle ambigue producono disaccordo che non ha niente a che vedere con la qualità degli annotatori. Fai un piccolo pilota per far emergere i problemi prima di andare in scala. Mescola i controlli invece di affidarti a uno solo, perché verifiche di attenzione, elementi gold e ridondanza intercettano cose diverse. Parti da soglie larghe e stringile quando avrai visto dei dati veri. Dai un riscontro agli annotatori quando puoi. Continua a monitorare, perché la qualità cala man mano che la gente si stanca. E metti per iscritto come tratti i casi limite, così le decisioni restano coerenti.

Per la configurazione dell'avvio degli annotatori, vedi la documentazione sulla fase di formazione.

Il controllo qualità dell'annotazione funziona meglio a strati:

StrategiaCome si realizzaQuando controllare
Verifiche di attenzioneQuestionari surveyflowDurante l'annotazione
Elementi goldMescolati nei datiDopo la raccolta
RidondanzaPiù annotatori per elementoDopo la raccolta
Metriche di accordoScript PythonDopo la raccolta
Analisi dei tempiMarcature temporali delle annotazioniDopo la raccolta
Funzioni della piattaformaImpostazioni di Prolific/MTurkPrima e durante la raccolta

Gran parte di questa analisi avviene dopo la raccolta, con script di post-elaborazione. Progetta quella pipeline prima di raccogliere qualsiasi cosa, così ti assicuri di registrare i campi che ti serviranno.

Prossimi passi


Per saperne di più sui flussi di annotazione, vedi la documentazione sugli schemi di annotazione.