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.
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
Il quadro d'insieme
Nessuna verifica basta da sola, quindi quasi tutti i progetti ne sovrappongono alcune:
- Verifiche di attenzione: controllano che gli annotatori stiano davvero seguendo il task
- Ridondanza: raccogliere più annotazioni per ogni elemento
- Metriche di accordo: misurano la coerenza tra annotatori
- Formazione e linee guida: servono a far capire il task
- 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.
annotation_task_name: "Sentiment Annotation with Checks"
surveyflow:
on: true
order:
- survey_instructions
- annotation
- survey_attention_check
- annotation
- survey_completionLe domande di verifica si definiscono come una pagina di questionario:
# 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 AgreeIl 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:
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 systemSu 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:
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:
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 kappa | Interpretazione |
|---|---|
| < 0.20 | Accordo scarso |
| 0.21 - 0.40 | Accordo discreto |
| 0.41 - 0.60 | Accordo moderato |
| 0.61 - 0.80 | Accordo sostanziale |
| 0.81 - 1.00 | Accordo quasi perfetto |
Potato mette a disposizione verifiche di attenzione, elementi gold e il monitoraggio dell'accordo tra annotatori per tenere sotto controllo la qualità:

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
- Prepara un insieme di elementi con risposte corrette chiare e non ambigue
- Falli etichettare da esperti
- Mescolali ai dati di annotazione ordinari
[
{
"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:
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_scoresIndicatori 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
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:
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 issuesBuone 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.
Riepilogo
Il controllo qualità dell'annotazione funziona meglio a strati:
| Strategia | Come si realizza | Quando controllare |
|---|---|---|
| Verifiche di attenzione | Questionari surveyflow | Durante l'annotazione |
| Elementi gold | Mescolati nei dati | Dopo la raccolta |
| Ridondanza | Più annotatori per elemento | Dopo la raccolta |
| Metriche di accordo | Script Python | Dopo la raccolta |
| Analisi dei tempi | Marcature temporali delle annotazioni | Dopo la raccolta |
| Funzioni della piattaforma | Impostazioni di Prolific/MTurk | Prima 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
- Approfondisci il calcolo dell'accordo tra annotatori
- Configura l'integrazione con Prolific per l'annotazione in crowdsourcing
- Imposta le fasi di formazione per l'avvio degli annotatori
Per saperne di più sui flussi di annotazione, vedi la documentazione sugli schemi di annotazione.