Information Extraction › Evaluation

Michael BrenndoerferFebruary 4, 20268 min read
Language AI HandbookAll chapters
Part 63 of 67LLM Applications
Chapter 481Information Extraction › Evaluation
Reading section 7 of 10 · Evaluation · 8 minSection 7 of 10 · 8 min

Book contents

Section 7 of 10 · 8 min read

Information Extraction › EvaluationOne section · Sections in this chapter7 / 10 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Evaluating IE systems requires task-specific metrics. The evaluation philosophy is the same across all IE tasks: partial credit is not given. Either a prediction matches the gold annotation exactly, or it counts as an error.

For NER, a prediction is correct only if both the span boundaries and the entity type match exactly. The standard metrics are entity-level precision, recall, and F1. To understand why these are defined at the entity level rather than the token level, consider a system that correctly identifies the tokens "New" and "York" but labels them as two separate entities instead of one "New York" span: token-level accuracy would be high, but entity-level evaluation would mark this as an error because the correct span boundary is not reproduced.

Precision measures how many predicted entities are correct:

Precision=∣TP∣∣TP∣+∣FP∣\text{Precision} = \frac{|\text{TP}|}{|\text{TP}| + |\text{FP}|}

Recall measures how many gold entities the model successfully predicted:

Recall=∣TP∣∣TP∣+∣FN∣\text{Recall} = \frac{|\text{TP}|}{|\text{TP}| + |\text{FN}|}

The harmonic mean of precision and recall, F1, provides a single balanced score:

F1=2⋅Precision⋅RecallPrecision+Recall\text{F1} = \frac{2 \cdot \text{Precision} \cdot \text{Recall}}{\text{Precision} + \text{Recall}}

where:

  • ∣TP∣|\text{TP}| is the count of True Positives: predicted spans that match a gold span in both token boundaries and entity type
  • ∣FP∣|\text{FP}| is the count of False Positives: predicted spans with no matching gold span (incorrect prediction or wrong type)
  • ∣FN∣|\text{FN}| is the count of False Negatives: gold spans that the model failed to predict entirely

The harmonic mean is used rather than the arithmetic mean because it penalizes imbalance between precision and recall more heavily. A system with precision 1.0 and recall 0.0 would have an arithmetic mean of 0.5 but an F1 of 0.0, correctly reflecting that the system is useless because it extracts nothing.

For relation extraction, evaluation is similarly span-based: a predicted triple (subject, predicate, object) is correct only when all three components match the gold annotation. This means RE F1 scores are always lower than NER F1 scores on the same document: a correct relation requires a correct subject entity AND a correct object entity AND a correct relation type. If the NER system has F1 of 0.90, the upper bound on RE F1 is approximately 0.902≈0.810.90^2 \approx 0.81, even with a perfect relation classifier. This compounding effect is why end-to-end IE pipelines are evaluated separately from their individual components, and why improvements in NER propagate through to RE.

For structured output, schema validation is a minimum bar (did the model produce valid JSON with all required fields?). Beyond that, field-level accuracy measures what fraction of fields are correctly populated, and document-level accuracy measures what fraction of complete records are perfect. Document-level accuracy is a demanding metric: a record with nine correct fields and one wrong field scores zero. For applications where a partially correct record is still useful (e.g., database entries that can be manually corrected), field-level accuracy is more informative.

In[17]:
Code
def compute_ner_metrics(gold_entities: list, pred_entities: list) -> dict:
    """
    Compute NER precision, recall, and F1.
    Each entity is a dict with 'text', 'label', 'start', 'end'.
    A prediction is correct if span boundaries and label both match gold.
    """
    gold_set = {(e["start"], e["end"], e["label"]) for e in gold_entities}
    pred_set = {(e["start"], e["end"], e["label"]) for e in pred_entities}

    tp = len(gold_set & pred_set)
    fp = len(pred_set - gold_set)
    fn = len(gold_set - pred_set)

    precision = tp / (tp + fp) if (tp + fp) > 0 else 0.0
    recall = tp / (tp + fn) if (tp + fn) > 0 else 0.0
    f1 = (
        2 * precision * recall / (precision + recall)
        if (precision + recall) > 0
        else 0.0
    )

    return {
        "precision": precision,
        "recall": recall,
        "f1": f1,
        "tp": tp,
        "fp": fp,
        "fn": fn,
    }


# Simulate gold vs. predicted entities
gold = [
    {"text": "Apple", "label": "ORG", "start": 0, "end": 5},
    {"text": "Beats Electronics", "label": "ORG", "start": 16, "end": 34},
    {"text": "$3 billion", "label": "MONEY", "start": 39, "end": 49},
    {"text": "May 2014", "label": "DATE", "start": 53, "end": 61},
    {"text": "Tim Cook", "label": "PERSON", "start": 63, "end": 71},
    {"text": "Cupertino", "label": "GPE", "start": 110, "end": 119},
    {"text": "California", "label": "GPE", "start": 121, "end": 131},
]

# Simulate a prediction that misses one entity and has one wrong type
pred = [
    {"text": "Apple", "label": "ORG", "start": 0, "end": 5},
    {"text": "Beats Electronics", "label": "ORG", "start": 16, "end": 34},
    {"text": "$3 billion", "label": "MONEY", "start": 39, "end": 49},
    {"text": "May 2014", "label": "DATE", "start": 53, "end": 61},
    {"text": "Tim Cook", "label": "PERSON", "start": 63, "end": 71},
    # Missing: Cupertino
    {
        "text": "California",
        "label": "LOC",
        "start": 121,
        "end": 131,
    },  # Wrong type: LOC not GPE
]

metrics = compute_ner_metrics(gold, pred)
Out[18]:
Console
NER Evaluation Results:
  True Positives:  5
  False Positives: 1
  False Negatives: 2
  Precision: 0.833
  Recall:    0.714
  F1 Score:  0.769

The precision of 1.0 reflects that every predicted entity is correct on its own terms, but the recall and F1 drop because of the missed entity (Cupertino) and the misclassified type (California labeled as LOC instead of GPE). In practice, NER errors cluster around rare entity types, boundary cases (multi-word entities), and ambiguous surface forms. The confusion between LOC and GPE is characteristic: geographic locations that are also political entities are systematically difficult, and different annotation guidelines disagree on the correct label.

The following chart shows how NER errors are distributed across error types (false positives, false negatives, and type errors) at different system confidence thresholds, illustrating the precision-recall tradeoff in practice.

Out[19]:
Visualization
Stacked bar chart showing how NER error types shift from false negatives to false positives as the confidence threshold decreases.
Distribution of NER error types across confidence thresholds. At high thresholds the system is cautious and makes mostly false negatives (missed entities). At low thresholds it becomes permissive and produces more false positives (incorrect predictions). The optimal threshold minimizes total errors rather than either error type alone.
Line plot showing precision-recall curves for PER, ORG, LOC, and MISC entity types.
Precision-recall curves for NER broken down by entity type on a news corpus. Person (PER) and Organization (ORG) types achieve higher balanced F1, showing their more consistent surface forms. Miscellaneous categories show wider gaps between precision and recall, showing greater ambiguity in what qualifies as a miscellaneous entity.

Evaluating LLM-Based Extraction

Evaluating LLM-based structured extraction introduces additional complexity beyond traditional NER and RE metrics. The output is a structured record rather than a sequence of labels, so evaluation must compare records field by field.

The simplest approach is exact string match per field: the extracted company name "Apple Inc." does not match the gold "Apple" even though they refer to the same entity. This motivates normalized evaluation, where both the gold and predicted values are normalized before comparison. For monetary values, normalization converts all forms to a canonical integer; for dates, it converts all forms to ISO 8601; for company names, it maps common abbreviations and suffixes to a canonical form.

A second challenge is evaluating null fields: when the model correctly returns null for a field that has no value in the source text, that is a true negative, and it should contribute positively to precision but not to recall. Traditional precision and recall formulas do not naturally handle true negatives in structured extraction, because F1 is defined over positive predictions. A common pragmatic solution is to exclude null fields from the denominator when computing field-level accuracy, and to separately track the null prediction error rate (how often the model predicts null when a value is present, or predicts a value when the text contains none).