Faza 05 · lecția 07

Etichetarea POS și analiza sintactică

Scopul lecției: Gramatica a ieșit din modă pentru o vreme. Apoi fiecare flux LLM a avut nevoie să valideze extragerea structurată și a revenit.

Versiunea curentă AlexBred.com: primele 100 de lecții ale programului în limba română.

Curs
AI Engineering from Scratch
Fază
NLP — de la fundamente la subiecte avansate
Lectură
15 min.
Verificat
Cuprinsul lecției
  1. Problema
  2. Conceptul
  3. Construiți
  4. Pasul 1: baza cu eticheta cea mai frecventă
  5. Pasul 2: etichetator HMM cu bigrame
  6. Pasul 3: de ce etichetatorii moderni depășesc aceasta
  7. Pasul 4: schița analizei dependențelor
  8. Folosiți
  9. Unde contează încă aceasta în 2026
  10. Livrați
  11. Exerciții
  12. Termeni-cheie
  13. Lecturi suplimentare

Gramatica a ieșit din modă pentru o vreme. Apoi fiecare flux LLM a avut nevoie să valideze extragerea structurată și a revenit.

Tip: Construire Limbaje: Python Cerințe prealabile: Faza 5 · 01 (Prelucrarea textului), Faza 2 · 14 (Naive Bayes) Timp: ~45 de minute

Problema

Lecția 01 a promis că lematizarea are nevoie de o etichetă a părții de vorbire. Fără să știe că running este verb, un lematizator nu îl poate reduce la run. Fără să știe că better este adjectiv, nu îl poate reduce la good.

Acea promisiune ascundea un subdomeniu întreg. Etichetarea părților de vorbire atribuie categorii gramaticale. Analiza sintactică recuperează structura arborescentă a propoziției: care cuvânt modifică pe care, ce verb guvernează ce argumente. NLP clasic a petrecut douăzeci de ani rafinându-le pe amândouă. Apoi învățarea profundă le-a redus la o sarcină de clasificare a tokenurilor peste un Transformer preantrenat, iar comunitatea de cercetare a trecut mai departe.

Nu și comunitatea aplicată. Fiecare flux de extragere structurată folosește încă POS și arbori de dependență în culise. JSON-ul generat de LLM este validat în raport cu constrângeri gramaticale. Sistemele de întrebări și răspunsuri descompun interogările folosind analize de dependență. Evaluatorii calității traducerii automate verifică alinierea arborilor de analiză.

Merită să le cunoașteți. Această lecție prezintă seturile de etichete, bazele de referință și punctul în care opriți implementarea de la zero și apelați spaCy.

Notă tehnică a traducerii: Utilizarea POS sau a dependențelor nu este universală în fluxurile LLM ori de extragere structurată. JSON-ul se validează în primul rând prin sintaxă, schemă și reguli de domeniu; constrângerile gramaticale pot fi utile pentru text natural, dar nu validează singure o extracție corectă. Evaluarea traducerii automate și a întrebărilor-răspunsurilor folosește multe metode, iar arborii de analiză sunt doar una dintre opțiuni.

Conceptul

Etichetarea POS marchează fiecare token cu o categorie gramaticală. Setul de etichete Penn Treebank (PTB) este implicit pentru engleză. Are 36 de etichete, cu distincții pe care cititorul ocazional le consideră migăloase: NN substantiv singular, NNS substantiv plural, NNP substantiv propriu singular, VBD verb la trecut, VBZ verb la prezent, persoana a III-a singular, și așa mai departe. Setul Universal Dependencies (UD) este mai grosier (17 etichete) și independent de limbă; a devenit implicit pentru lucrul între limbi.

Pisicile/DET erau/AUX alergând/VERB la/ADP 3pm/NOUN ./PUNCT

Analiza sintactică produce un arbore. Două stiluri majore:

  • Analiza pe constituenți. Grupurile nominale, verbale și prepoziționale se imbrică unele în altele. Ieșirea este un arbore de categorii neterminale (NP, VP, PP), cu cuvintele ca frunze.
  • Analiza dependențelor. Fiecare cuvânt are un singur cuvânt-cap de care depinde, etichetat cu o relație gramaticală. Ieșirea este un arbore în care fiecare muchie este un triplet (cap, dependent, relație).

Notă tehnică a traducerii: Regula unui singur cap descrie arborele de dependențe de bază pentru tokenurile nerădăcină; rădăcina nu are cap lexical. Nu este o regulă pentru orice reprezentare: Enhanced Universal Dependencies este un graf care poate adăuga dependențe și noduri goale pentru elipsă, iar tokenurile pot participa la relații suplimentare. Consultați sintaxa UD enhanced.

Analiza dependențelor a câștigat în anii 2010 fiindcă se generalizează curat între limbi, mai ales în cele cu ordine liberă a cuvintelor.

alergând este ROOT
pisicile este nsubj al lui alergând
erau este aux al lui alergând
la este prep al lui alergând
3pm este pobj al lui la

Ilustrație originală: etichete POS și analiză de dependență

Ilustrație originală din assets/pos-parse.svg al lecției-sursă. Markdownul-sursă nu are o referință explicită, însă SVG-ul descrie direct exemplul acestei lecții: etichetele POS și arborele de dependență pentru aceeași propoziție. Diagrama este păstrată fără modificări; etichetele originale în limba engleză sunt explicate în proză.

Notă tehnică a traducerii: Exemplele combină convenții. Etichetele POS din primul bloc sunt UD, însă relațiile prep și pobj din al doilea bloc sunt specifice unor scheme englezești precum cele folosite de spaCy, nu relațiile UD de bază (unde apar, de exemplu, case și obl). 3pm poate primi și o etichetă diferită în funcție de tokenizer, limbă, model și schemă. Comparați întotdeauna tagsetul și schema de dependențe ale modelului ales. Consultați Universal Dependencies.

Construiți

Pasul 1: baza cu eticheta cea mai frecventă

Cel mai simplist etichetator POS care funcționează. Pentru fiecare cuvânt, preziceți eticheta pe care a avut-o cel mai des la antrenare.

from collections import Counter, defaultdict


def train_mft(train_examples):
    word_tag_counts = defaultdict(Counter)
    all_tags = Counter()
    for tokens, tags in train_examples:
        for token, tag in zip(tokens, tags):
            word_tag_counts[token.lower()][tag] += 1
            all_tags[tag] += 1
    word_best = {w: c.most_common(1)[0][0] for w, c in word_tag_counts.items()}
    default_tag = all_tags.most_common(1)[0][0]
    return word_best, default_tag


def predict_mft(tokens, word_best, default_tag):
    return [word_best.get(t.lower(), default_tag) for t in tokens]

Pe corpusul Brown, această bază atinge ~85% acuratețe. Nu este bine, dar este pragul sub care nu ar trebui să cadă niciun model serios.

Notă tehnică a traducerii: Acuratețea bazei MFT depinde de partea de corpus Brown, împărțirea antrenare/test, normalizare, setul de etichete și tratarea cuvintelor nevăzute. O etichetă implicită globală favorizează clasa majoritară; nu tratați aproximativ 85% drept un prag reproductibil sau universal.

Pasul 2: etichetator HMM cu bigrame

Modelați probabilitatea comună a secvenței:

P(tags, words) = prod P(tag_i | tag_{i-1}) * P(word_i | tag_i)

Două tabele: probabilități de tranziție (eticheta dată eticheta anterioară) și probabilități de emisie (cuvântul dată eticheta). Estimați-le pe amândouă din numărări cu netezire Laplace. Decodați cu Viterbi (programare dinamică peste rețeaua de etichete).

import math


def train_hmm(train_examples, alpha=0.01):
    transitions = defaultdict(Counter)
    emissions = defaultdict(Counter)
    tags = set()
    vocab = set()

    for tokens, ts in train_examples:
        prev = "<BOS>"
        for token, tag in zip(tokens, ts):
            transitions[prev][tag] += 1
            emissions[tag][token.lower()] += 1
            tags.add(tag)
            vocab.add(token.lower())
            prev = tag
        transitions[prev]["<EOS>"] += 1

    return transitions, emissions, tags, vocab


def log_prob(table, given, key, smooth_denom, alpha):
    return math.log((table[given].get(key, 0) + alpha) / smooth_denom)


def viterbi(tokens, transitions, emissions, tags, vocab, alpha=0.01):
    tags_list = list(tags)
    n = len(tokens)
    V = [[0.0] * len(tags_list) for _ in range(n)]
    back = [[0] * len(tags_list) for _ in range(n)]

    for j, tag in enumerate(tags_list):
        em_denom = sum(emissions[tag].values()) + alpha * (len(vocab) + 1)
        tr_denom = sum(transitions["<BOS>"].values()) + alpha * (len(tags_list) + 1)
        tr = log_prob(transitions, "<BOS>", tag, tr_denom, alpha)
        em = log_prob(emissions, tag, tokens[0].lower(), em_denom, alpha)
        V[0][j] = tr + em
        back[0][j] = 0

    for i in range(1, n):
        for j, tag in enumerate(tags_list):
            em_denom = sum(emissions[tag].values()) + alpha * (len(vocab) + 1)
            em = log_prob(emissions, tag, tokens[i].lower(), em_denom, alpha)
            best_prev = 0
            best_score = -1e30
            for k, prev_tag in enumerate(tags_list):
                tr_denom = sum(transitions[prev_tag].values()) + alpha * (len(tags_list) + 1)
                tr = log_prob(transitions, prev_tag, tag, tr_denom, alpha)
                score = V[i - 1][k] + tr + em
                if score > best_score:
                    best_score = score
                    best_prev = k
            V[i][j] = best_score
            back[i][j] = best_prev

    last_best = max(range(len(tags_list)), key=lambda j: V[n - 1][j])
    path = [last_best]
    for i in range(n - 1, 0, -1):
        path.append(back[i][path[-1]])
    return [tags_list[j] for j in reversed(path)]

Un HMM cu bigrame pe Brown atinge ~93% acuratețe. Saltul de la 85% la 93% provine în mare parte din probabilitățile de tranziție — modelul învață că DET NOUN este frecvent, iar NOUN DET este rar.

Notă tehnică a traducerii: Fragmentul este o schiță HMM, nu un decodor complet robust: presupune cel puțin un token, folosește defaultdict și Counter importate în pasul anterior și nu adaugă log P(<EOS> | tag_final) la alegerea lui last_best, astfel încât nu maximizează probabilitatea unei secvențe terminate. Pentru o probabilitate completă a secvenței, comparați și tranziția finală; tratați separat intrarea goală și fixați ordinea etichetelor pentru reproducibilitate. În plus, zip(tokens, tags) taie silențios perechile când lungimile diferă, iar un set de antrenare gol nu poate stabili eticheta implicită ori spațiul de stări; validați aceste precondiții. Scorul de aproximativ 93% rămâne dependent de protocolul Brown.

Pasul 3: de ce etichetatorii moderni depășesc aceasta

Probabilitățile de tranziție + emisie sunt locale. Ele nu pot surprinde faptul că saw este substantiv în „I bought a saw”, dar verb în „I saw the movie.” Un CRF cu caracteristici arbitrare (sufix, forma cuvântului, cuvântul anterior și următor, cuvântul însuși) atinge ~97%. Un BiLSTM-CRF sau Transformer atinge ~98%+.

Plafonul acestei sarcini este stabilit de dezacordul dintre adnotatori. Adnotatorii umani sunt de acord în proporție de circa 97% pe Penn Treebank. Modelele de peste 98% probabil supraînvață setul de test.

Notă tehnică a traducerii: Procentele CRF, BiLSTM-CRF, Transformer și acordul uman nu sunt plafoane universale. Ele variază cu versiunea corpusului, tagsetul, splitul, tokenizarea, procedura de evaluare și domeniul. Un scor mai mare nu demonstrează singur supraînvățarea; verificați separarea datelor, erorile, incertitudinea și generalizarea în afara distribuției.

Pasul 4: schița analizei dependențelor

Analiza completă a dependențelor de la zero depășește scopul; tratamentul canonic din manual se află la Jurafsky și Martin. Două familii clasice de cunoscut:

  • Analizoarele bazate pe tranziții (arc-eager, arc-standard) se comportă ca un analizor shift-reduce: citesc tokenuri, le pun pe o stivă și aplică acțiuni de reducere care creează arce. Decodarea greedy este rapidă. Implementarea clasică este MaltParser. Versiunea neuronală modernă: analizorul bazat pe tranziții al lui Chen și Manning.
  • Analizoarele bazate pe graf punctează muchiile posibile cap–dependent, dar decodorul depinde de restricția structurală. Algoritmul lui Eisner folosește programare dinamică pentru arbori proiectivi, fără arce care se intersectează; pentru arbori neproiectivi se poate folosi un arbore de acoperire maximă cu Chu–Liu–Edmonds. Modelul biaffine Dozat–Manning punctează arcele, iar decodorul concret se alege separat. Viteza și acuratețea depind de model, date, proiectivitate și benchmark. Consultați Eisner (1996) și Dozat–Manning (2017).

Pentru cea mai mare parte a muncii aplicate, apelați spaCy:

import spacy

nlp = spacy.load("en_core_web_sm")
doc = nlp("The cats were running at 3pm.")
for token in doc:
    print(f"{token.text:10s} tag={token.tag_:5s} pos={token.pos_:6s} dep={token.dep_:10s} head={token.head.text}")
The        tag=DT    pos=DET    dep=det        head=cats
cats       tag=NNS   pos=NOUN   dep=nsubj      head=running
were       tag=VBD   pos=AUX    dep=aux        head=running
running    tag=VBG   pos=VERB   dep=ROOT       head=running
at         tag=IN    pos=ADP    dep=prep       head=running
3pm        tag=NN    pos=NOUN   dep=pobj       head=at
.          tag=.     pos=PUNCT  dep=punct      head=running

Citiți coloana dep de jos în sus și structura gramaticală a propoziției devine evidentă.

Notă tehnică a traducerii: en_core_web_sm este un model separat de pachetul spaCy; rezultatele, etichetele și disponibilitatea depind de versiunea modelului și a bibliotecii. Ieșirea afișată este un exemplu, nu o interfață stabilă pentru fiecare versiune. Fixați versiunea și modelul, apoi validați pe propoziții reprezentative. Consultați modelele spaCy și atributele lingvistice.

Folosiți

Fiecare bibliotecă NLP de producție livrează etichetatoare POS și analizoare de dependență ca parte dintr-un flux standard.

  • spaCy (en_core_web_sm / md / lg / trf). Rapid, precis, integrat cu tokenizarea + NER + lematizarea. token.tag_ (Penn), token.pos_ (UD), token.dep_ (relația de dependență).
  • Stanford NLP (stanza). Succesorul Stanford pentru CoreNLP. De ultimă generație în peste 60 de limbi.
  • trankit. Bazat pe Transformere, cu acuratețe bună pentru UD.
  • NLTK. pos_tag. Utilizabil, lent, mai vechi. Potrivit pentru predare.

Notă tehnică a traducerii: Alegerea bibliotecii, acoperirea limbilor, viteza și acuratețea depind de model, versiune, licență, hardware, domeniu și benchmark. „De ultimă generație” și „cea mai mare acuratețe UD” sunt afirmații temporale care trebuie verificate pe setul de date și versiunile concrete; nu presupuneți echivalența etichetelor sau a relațiilor între biblioteci.

Unde contează încă aceasta în 2026

  • Lematizare. Lecția 01 are nevoie de POS pentru a lematiza corect. Întotdeauna.
  • Extragere structurată din ieșiri LLM. Validați că o propoziție generată respectă constrângeri gramaticale (de exemplu, acordul subiect–verb, modificatori obligatorii).
  • Sentiment bazat pe aspecte. Analizele de dependență arată care adjectiv modifică ce substantiv.
  • Înțelegerea interogării. „movies directed by Wes Anderson starring Bill Murray” se descompune în constrângeri structurate prin analiză.
  • Transfer între limbi. Etichetele UD și relațiile de dependență sunt independente de limbă, permițând analiză structurată zero-shot a limbilor noi.
  • Fluxuri cu puțin calcul. Dacă nu puteți livra un Transformer, POS + analiză de dependență + gazetteer vă duc surprinzător de departe.

Notă tehnică a traducerii: POS-ul nu este necesar pentru orice lematizator, iar analizele de dependență automate pot fi fragile la text informal, ambiguitate, erori de tokenizare și limbi ori domenii slab acoperite. UD furnizează o schemă comună, nu garantează transfer zero-shot sau calitate egală. Pentru constrângeri operaționale, măsurați latența și eroarea pe datele țintă înainte de a trata analiza sintactică drept validare.

Livrați

Salvați ca outputs/skill-grammar-pipeline.md:

---
name: grammar-pipeline
description: Proiectează un flux clasic POS + dependențe pentru o sarcină NLP din aval.
version: 1.0.0
phase: 5
lesson: 07
tags: [nlp, pos, parsing]
---

Pentru o sarcină din aval (extragere de informații, validarea rescrierii, descompunerea interogării, lematizare), produceți:

1. Setul de etichete de folosit. Penn Treebank pentru fluxuri englezești vechi, Universal Dependencies pentru lucru multilingv sau între limbi.
2. Biblioteca. spaCy pentru cea mai mare parte a producției, stanza pentru multilingvism de nivel academic, trankit pentru cea mai mare acuratețe UD. Numiți ID-ul exact al modelului.
3. Tiparul de integrare. Arătați cele 3–5 linii care apelează biblioteca și consumă atributele necesare (`.pos_`, `.dep_`, `.head`).
4. Modul de eșec de testat. Ambiguitatea substantiv–verb (`saw`, `book`, `can`) și ambiguitatea de atașare PP sunt capcanele clasice. Eșantionați 20 de ieșiri și inspectați-le vizual.

Refuzați să recomandați construirea propriului analizor. Construirea analizoarelor de la zero este un proiect de cercetare, nu o sarcină de aplicație. Semnalați orice flux care consumă etichete POS fără a trata variantele cu litere mici/mari ca fragil.

Notă tehnică a traducerii: Recomandarea unei biblioteci trebuie să țină cont de suportul efectiv pentru limbă, model și licență; „cea mai mare acuratețe” nu se poate atribui universal. Inspecția a 20 de exemple este utilă pentru depanare, dar nu înlocuiește un set etichetat, metrici per relație și o analiză de erori. Un parser personalizat poate fi justificat în cercetare sau pentru un domeniu foarte specializat, dacă resursele și evaluarea susțin acest lucru.

Exerciții

  1. Ușor. Folosind baza cu eticheta cea mai frecventă pe un corpus mic etichetat (de exemplu, submulțimea Brown din NLTK), măsurați acuratețea pe propoziții păstrate separat. Verificați rezultatul de ~85%.
  2. Mediu. Antrenați HMM-ul cu bigrame de mai sus și raportați precizie/reamintire per etichetă. Ce etichete confundă HMM-ul cel mai des?
  3. Dificil. Folosiți analiza de dependență spaCy pentru a extrage triple subiect–verb–obiect dintr-un eșantion de 1000 de propoziții. Evaluați pe 50 de triple etichetate manual. Documentați unde eșuează extragerea (adesea pasive, coordonări și subiecți elidați).

Notă tehnică a traducerii: Pentru exercițiul 3, definiți înainte convențiile pentru pasiv, coordonări, propoziții relative, control și subiecți inexistenți. 50 de exemple pot servi drept verificare exploratorie, nu drept estimare stabilă a calității; raportați eșantionarea, acordul adnotatorilor și incertitudinea.

Termeni-cheie

Termen Ce spun oamenii Ce înseamnă de fapt
Etichetă POS Tipul cuvântului Categorie gramaticală. PTB are 36; UD are 17.
Penn Treebank Set standard de etichete Specific limbii engleze. Timpuri verbale și număr al substantivului cu granularitate fină.
Universal Dependencies Set de etichete multilingv Mai grosier decât PTB; neutru față de limbă; implicit pentru lucrul între limbi.
Analiza dependențelor Arborele propoziției Fiecare cuvânt nerădăcină are un cap, iar fiecare muchie are o relație gramaticală.
Viterbi Programare dinamică Găsește secvența de etichete cu probabilitatea cea mai mare, date emisiile și tranzițiile.

Notă tehnică a traducerii: Numărul etichetelor PTB și UD depinde de convenția folosită, de includerea punctuației și de versiune. Într-un arbore de dependențe, rădăcina nu are cap lexical; afirmația „fiecare cuvânt are un cap” este corectă numai pentru tokenurile nerădăcină. Viterbi oferă maximul în raport cu modelul și parametrii furnizați, nu garanția unei analize lingvistice corecte.

Lecturi suplimentare

Sursă: Originalul în limba engleză

Navigare: ← Lecția 05.06 — Recunoașterea entităților denumite (NER) · Faza 5 — NLP: de la fundamente la subiecte avansate · Catalog complet