Skip to content
Guides6 min read

Inter-Annotator-Übereinstimmung messen

Cohens Kappa, Fleiss' Kappa und Krippendorffs Alpha für Potato-Annotationsprojekte berechnen und deuten, mit Python-Codebeispielen und Hinweisen zur Interpretation.

Potato Team

Die Inter-Annotator-Übereinstimmung (IAA) misst, wie einheitlich verschiedene Annotierende dieselben Elemente labeln. Ist die Übereinstimmung hoch, kannst du den Labels trauen. Ist sie niedrig, liegt es meist entweder an einer unklaren Richtlinie oder an einer Aufgabe, die schlicht subjektiv ist.

Ein Übereinstimmungsmaß wählen: bei zwei Beurteilenden Cohens Kappa, bei vielen Beurteilenden Fleiss' Kappa, bei ordinalen oder fehlenden Daten Krippendorffs AlphaWelches Übereinstimmungsmaß passt

Warum überhaupt messen?

Ein paar Gründe, warum sich der Aufwand lohnt. Niedrige Übereinstimmung verweist meist auf Anweisungen, die neu geschrieben gehören, der Wert ist also zugleich eine Prüfung deiner Richtlinien. Er sagt dir außerdem, wie schwierig die Aufgabe wirklich ist, denn manche Fragen haben keine eindeutig richtige Antwort. Du erkennst, wer von den Annotierenden mehr Einarbeitung braucht. Und wenn du publizierst, erwarten Gutachtende eine Angabe zur Übereinstimmung. Nicht zuletzt beeinflusst das Maß, wie du mehrere Annotierende zu einem einzelnen Label zusammenführst.

Wie Potato das von Anfang bis Ende handhabt, steht in der Quelldokumentation.

Übereinstimmungsmaße

Cohens Kappa (2 Annotierende)

Für den Vergleich zweier Annotierender bei kategorialen Daten:

text
κ = (Po - Pe) / (1 - Pe)

Dabei gilt:

  • Po = beobachtete Übereinstimmung
  • Pe = zufällig erwartete Übereinstimmung

Interpretation:

KappaInterpretation
< 0Schlechter als Zufall
0.01-0.20Gering
0.21-0.40Ausreichend
0.41-0.60Mittelmäßig
0.61-0.80Beachtlich
0.81-1.00Nahezu perfekt

Fleiss' Kappa (3+ Annotierende)

Für drei oder mehr Annotierende bei kategorialen Daten:

yaml
quality_control:
  agreement:
    metrics:
      - fleiss_kappa

Die Interpretationsskala ist dieselbe wie bei Cohens Kappa.

Krippendorffs Alpha

Das ist die flexibelste der drei Kennzahlen. Sie kommt mit beliebig vielen Annotierenden zurecht, verkraftet fehlende Daten und funktioniert bei nominalen, ordinalen, Intervall- und Verhältnisdaten.

yaml
quality_control:
  agreement:
    metrics:
      - krippendorff_alpha
    alpha_level: nominal  # or ordinal, interval, ratio

Interpretation:

  • α ≥ 0.80: verlässlich
  • 0.67 ≤ α < 0.80: vorläufig akzeptabel
  • α < 0.67: nicht verlässlich

Übereinstimmung in Potato konfigurieren

Grundeinstellung

yaml
quality_control:
  agreement:
    enabled: true
    calculate_on_overlap: true
 
    metrics:
      - cohens_kappa
      - fleiss_kappa
      - krippendorff_alpha
 
    # Per annotation scheme
    per_scheme: true
 
    # Reporting
    report_interval: 100  # Every 100 annotations
    export_file: agreement_report.json

Überlappung konfigurieren

yaml
quality_control:
  redundancy:
    # How many annotators per item
    annotations_per_item: 3
 
    # Minimum overlap for calculations
    min_overlap_for_agreement: 2
 
    # Sampling for agreement
    agreement_sample_size: 100  # Calculate on 100 items
    agreement_sample_method: random  # or stratified, all

Übereinstimmung berechnen

Im Dashboard

Potato zeigt die Übereinstimmungsmaße im Admin-Dashboard an:

yaml
quality_control:
  dashboard:
    show_agreement: true
    agreement_chart: true
    update_frequency: 60  # seconds

Über die API

bash
# Get current agreement metrics
curl http://localhost:8000/api/quality/agreement
 
# Response:
{
  "overall": {
    "fleiss_kappa": 0.72,
    "krippendorff_alpha": 0.75
  },
  "per_scheme": {
    "sentiment": {
      "fleiss_kappa": 0.78,
      "krippendorff_alpha": 0.80
    },
    "topic": {
      "fleiss_kappa": 0.65,
      "krippendorff_alpha": 0.68
    }
  },
  "sample_size": 150,
  "annotator_pairs": 10
}

Über die Kommandozeile

bash
# Calculate agreement from output files
potato agreement --annotations annotation_output/ --output agreement_report.json
 
# With specific metric
potato agreement --annotations annotation_output/ --metric krippendorff --level ordinal

Übereinstimmung bei verschiedenen Annotationstypen

Kategorial (Radio, Multiselect)

yaml
quality_control:
  agreement:
    schemes:
      sentiment:
        type: nominal
        metrics: [cohens_kappa, fleiss_kappa]
 
      urgency:
        type: ordinal  # Low < Medium < High
        metrics: [krippendorff_alpha]

Likert-Skalen

yaml
quality_control:
  agreement:
    schemes:
      quality_rating:
        type: ordinal
        metrics: [krippendorff_alpha, weighted_kappa]
 
        # Weighted kappa for ordinal
        weighting: linear  # or quadratic

Span-Annotationen

Spans sind kniffliger als kategoriale Labels, denn zwei Annotierende können sich beim Label einig sein und trotzdem uneins darüber, wo genau er anfängt und aufhört. NER braucht eine gesonderte Behandlung:

yaml
quality_control:
  agreement:
    schemes:
      entities:
        type: span
        span_matching: overlap  # or exact, token
 
        # What to compare
        compare: label_and_span  # or label_only, span_only
 
        # Overlap threshold for "match"
        overlap_threshold: 0.5
 
        metrics:
          - span_f1
          - span_precision
          - span_recall

Rangfolgen

yaml
quality_control:
  agreement:
    schemes:
      preference_rank:
        type: ranking
        metrics:
          - kendall_tau
          - spearman_rho

Paarweise gegen globale Übereinstimmung

Paarweise (jedes Paar einzeln)

yaml
quality_control:
  agreement:
    pairwise: true
    output_matrix: true  # Agreement matrix
 
# Output:
# annotator1 × annotator2: κ = 0.75
# annotator1 × annotator3: κ = 0.68
# annotator2 × annotator3: κ = 0.82

Global (alle Annotierenden)

yaml
quality_control:
  agreement:
    overall: true
    metrics:
      - fleiss_kappa  # Designed for 3+ annotators
      - krippendorff_alpha

Umgang mit niedriger Übereinstimmung

Problemstellen finden

yaml
quality_control:
  agreement:
    diagnostics:
      enabled: true
 
      # Items with most disagreement
      show_disagreed_items: true
      disagreement_threshold: 0.5
 
      # Labels with most confusion
      confusion_matrix: true
 
      # Annotators with low agreement
      per_annotator_agreement: true

Maßnahmen bei niedriger Übereinstimmung

yaml
quality_control:
  agreement:
    alerts:
      - threshold: 0.6
        action: notify
        message: "Agreement below 0.6 - review guidelines"
 
      - threshold: 0.4
        action: pause
        message: "Agreement critically low - pausing task"
 
    # Automatic guideline reminders
    show_guidelines_on_low_agreement: true
    guideline_threshold: 0.5

Vollständige Konfiguration

yaml
annotation_task_name: "Agreement-Tracked Annotation"
 
quality_control:
  # Redundancy setup
  redundancy:
    annotations_per_item: 3
    assignment_method: random
 
  # Agreement calculation
  agreement:
    enabled: true
 
    # Metrics
    metrics:
      - fleiss_kappa
      - krippendorff_alpha
 
    # Per-scheme configuration
    schemes:
      sentiment:
        type: nominal
        metrics: [fleiss_kappa, cohens_kappa]
 
      intensity:
        type: ordinal
        metrics: [krippendorff_alpha]
        alpha_level: ordinal
 
      entities:
        type: span
        span_matching: overlap
        overlap_threshold: 0.5
        metrics: [span_f1]
 
    # Calculation settings
    calculate_on_overlap: true
    min_overlap: 2
    sample_size: all  # or number
 
    # Pairwise analysis
    pairwise: true
    pairwise_output: agreement_matrix.csv
 
    # Diagnostics
    diagnostics:
      confusion_matrix: true
      disagreed_items: true
      per_annotator: true
 
    # Alerts
    alerts:
      - metric: fleiss_kappa
        threshold: 0.6
        action: notify
 
    # Reporting
    report_file: agreement_report.json
    report_interval: 50
 
  # Dashboard
  dashboard:
    show_agreement: true
    charts:
      - agreement_over_time
      - per_scheme_agreement
      - annotator_comparison

Ausgegebener Bericht

json
{
  "timestamp": "2024-10-25T15:30:00Z",
  "sample_size": 500,
  "annotators": ["ann1", "ann2", "ann3"],
 
  "overall_agreement": {
    "fleiss_kappa": 0.72,
    "krippendorff_alpha": 0.75
  },
 
  "per_scheme": {
    "sentiment": {
      "fleiss_kappa": 0.78,
      "confusion_matrix": {
        "Positive": {"Positive": 180, "Negative": 5, "Neutral": 15},
        "Negative": {"Positive": 8, "Negative": 165, "Neutral": 12},
        "Neutral": {"Positive": 12, "Negative": 10, "Neutral": 93}
      }
    }
  },
 
  "pairwise": {
    "ann1_ann2": 0.75,
    "ann1_ann3": 0.70,
    "ann2_ann3": 0.72
  },
 
  "per_annotator": {
    "ann1": {"avg_agreement": 0.73, "items_annotated": 500},
    "ann2": {"avg_agreement": 0.74, "items_annotated": 500},
    "ann3": {"avg_agreement": 0.71, "items_annotated": 500}
  },
 
  "most_disagreed_items": [
    {"id": "item_234", "disagreement_rate": 1.0},
    {"id": "item_567", "disagreement_rate": 0.67}
  ]
}

Bewährtes Vorgehen

Berechne die Übereinstimmung früh, statt bis zum Projektende zu warten, denn dann ist es zu spät, die Richtlinien noch zu reparieren. Wähle das Maß, das zu deinen Daten passt: nominal, ordinal oder Span. Kommt ein niedriger Wert heraus, sieh genauer hin, bevor du es den Annotierenden anlastest, denn oft liegt es an den Anweisungen. Nenne den Wert in jeder Veröffentlichung. Und leg dich auf eine akzeptable Schwelle fest, bevor du anfängst, nicht erst, nachdem du dein Ergebnis gesehen hast.

Ausführlicher zur Schätzung der Kompetenz bei uneinigen Annotierenden siehe die MACE-Dokumentation.

Nächste Schritte


Vollständige Dokumentation zur Übereinstimmung unter Benutzerverwaltung.