Informationsextraktion och NER
Kunna extrahera entiteter och relationer ur text och mäta precision/recall.
Förkunskaper
Intuition
NER märker upp spann i text: personer, organisationer, platser, datum, belopp. Standardformatet är BIO:
Anna B-PER
Svensson I-PER
arbetar O
på O
Volvo B-ORG
i O
Göteborg B-LOC
B = början på en entitet, I = inuti, O = utanför.
Två angreppssätt i dag:
| Finjusterad encoder | LLM med schema | |
|---|---|---|
| Data som krävs | 500+ märkta meningar | 0–20 exempel |
| Kostnad per dokument | mycket låg | hög |
| Nya entitetstyper | omträning | ändra prompten |
| Precision på inövade typer | högre | något lägre |
För stora volymer och fasta typer vinner encodern. För få dokument eller föränderliga typer vinner LLM:en.
Formellt
Utvärdering på entitetsnivå, inte tokennivå. Ett spann räknas som korrekt bara om både gränserna och typen stämmer. Det är hårdare än tokenvis mätning och är det som faktiskt spelar roll.
Ett fel som «Anna Svensson» → «Svensson» räknas alltså som både ett missat (FN) och ett felaktigt (FP) — inte som halvrätt. seqeval gör detta korrekt; en vanlig classification_report på tokennivå överskattar systematiskt.
Relationsextraktion går ett steg längre: hitta att «Anna Svensson» arbetar på «Volvo». Vanliga ansatser är parvis klassificering av entitetspar, eller en LLM med ett schema som kräver både entiteter och relationer i JSON.
Fallgropar som är specifika för svenska: sammansättningar («Volvochefen» innehåller en organisation), genitivformer, och att svenska NER-korpusar är betydligt mindre än engelska. KB-lab:s modeller och SUC-korpuset är utgångspunkterna.
Kod
from transformers import pipeline
from seqeval.metrics import classification_report
# Finjusterad svensk modell
ner = pipeline("ner", model="KBLab/bert-base-swedish-cased-ner", aggregation_strategy="simple")
for e in ner("Anna Svensson arbetar på Volvo i Göteborg sedan 2019."):
print(f"{e['entity_group']:6s} {e['word']:20s} {e['score']:.2f}")
# PER Anna Svensson 0.99
# ORG Volvo 0.98
# LOC Göteborg 0.99
# Utvärdering på ENTITETSNIVÅ
sant = [["B-PER", "I-PER", "O", "O", "B-ORG", "O", "B-LOC"]]
pred = [["B-PER", "I-PER", "O", "O", "B-ORG", "O", "O"]]
print(classification_report(sant, pred, digits=3))
# LLM-alternativ med schema
from pydantic import BaseModel
class Entitet(BaseModel):
text: str
typ: str # PER|ORG|LOC|TID|BELOPP
start: int
class Extraktion(BaseModel):
entiteter: list[Entitet]
Jämför alltid de två på ditt material innan du väljer — skillnaden i precision och kostnad varierar kraftigt med domänen.
Behärskning innebär
- Extraherar entiteter och relationer ur text
- Mäter precision och recall på entitetsnivå
- Väljer mellan finjusterad modell och LLM-extraktion
Logga in för att göra övningarna och bygga upp din behärskning.
Källor
- Kungliga biblioteket — KB-lab modeller — öppna modeller
- Hugging Face — dokumentation (Apache-2.0) — Apache-2.0