Il pre-processing per modelli Tier 2 in lingua italiana richiede una maturità avanzata rispetto al Tier 1, che si limita a pulizia base e normalizzazione. Mentre Tier 1 si concentra su rimozione di caratteri non validi e tokenizzazione generica, Tier 2 impone un’analisi morfologica profonda, gestione regionale del lessico e feature semantiche contestuali per massimizzare la performance del modello. Questo articolo esplora, passo dopo passo, una pipeline specialistica che va oltre il livello generico, con procedure dettagliate, esempi tecnici e best practice per garantire input NLP di altissima qualità.
1. Dalle fondamenta del Tier 1 al contesto avanzato del Tier 2
Il Tier 1 introduce pulizia essenziale: rimozione di emoji, tag HTML, coordinate geografiche e normalizzazione ortografica base con dizionari bilingual (es. italiani/italiano). Il Tier 2 estende questa base con analisi morfologica contestuale, gestione dialetti e varianti lessicali, e standardizzazione semantica. Ad esempio, la parola “c’è” nel dialetto romano, spesso usata come ellissi di “ci è”, richiede una regola specifica di mapping: non solo sostituzione a “ci è”, ma riconoscimento della struttura ellittica e contesto fraseologico.
Takeaway operativo: prima di ogni pipeline Tier 2, eseguire un’analisi POS fine-grained con `spaCy` in modalità italiana (`it_core_news_sm`) per identificare verbi in tempo passato, contrazione “non è” → “non’è”, aggettivi variabili (“macchina” vs “auto”), e frasi nominali ambigue (“banco” istituzione vs “banco” mobile).
2. Fase 1: Pulizia iniziale e normalizzazione con controllo linguistico avanzato
La rimozione di caratteri non validi va oltre i soli emoji e HTML: include coordinate geografiche (es. `(41.89193, 12.51133)`) filtrate con regex specifiche per testo italiano, es. `\b\d{1,6}[,]\s*\d{1,6}\b` per pattern latitudine/longitudine.
La normalizzazione ortografica si basa su dizionari bilingual (italiano/inglese) e regole di mapping contestuale:
– “tipo” → “tipo” (standard), “c’è” → “ci è” (solo in contesti colloquiali non strutturati), “fa’” → “fa”, “cosa” → “cosa” con accentazione obbligatoria in contesti formali.
– Esempio pratico:
import re
import re
def normalize_italian(text):
# Rimuove tag HTML: <.*?>
text = re.sub(r'<[^>]+>’, ”, text)
# Normalizza spazi con contrazione “non è” → “non’è”
text = re.sub(r'(non\s+è)’, ‘non’è’, text)
# Gestisce coordinate geografiche: (41.89193, 12.51133) → rimozione
text = re.sub(r’\b\(?\d{1,6}[\s,]\s*\d{1,6}\b’, ”, text)
# Accentazione formale: “cosa” → “cosa” (già corretto), “banco” → “banco” (già standard)
# Mappa contrazioni dialettali: esempio “c’è” → “ci è” solo in frasi colloquiali, altrimenti mantieni “ci è”
text = text.replace(“c’è”, “ci è”)
return text.strip()
Errore frequente: sovra-lemmatizzazione di verbi irregolari come “c’è” (forma intransitiva) confusa con “ci è”, perdendo contesto temporale. Risolto con POS tag: se POS = NOUN + AUX + PARTICLE, non lemmatizzare come verbo generico.
3. Fase 2: Gestione morfologica e sintattica con lemmatizzazione contestuale
L’uso di `spaCy` con modello `it_core_news_sm` consente lemmatizzazione precisa, ma richiede regole personalizzate per la morfologia italiana, ricca di flessioni verbali e morfemi complessi.
Esempio:
from spacy import displacy
from spacy.tokens import Token
def lemmatize_contestualmente(tok: Token) -> Token:
if tok.tag_ == “VERB” and tok.lemma_ in {“corro”, “correrò”, “fui”, “sono”} and tok.head.pos_ == “VERB”:
# Distingui tra passato prossimo e futuro: “corro” → “corro”, “correrò” → “correrò”, “fui” → “fui”, “sono” → “sono”
# Ma se “corrò” appare come passato lontano, usa contesto per correzione
if tok.dep_ == “neg” and tok.head.text == “cambiare” and tok.text == “corro”:
return tok # mantiene forma originale
# Usa regola di disambiguazione: se “corrò” seguito da “domani”, lemmatizza come passato prossimo
return tok # regola avanzata da integrare
return tok.lemma_
batch:
doc = spacy.load(“it_core_news_sm”)(“Il corro domani, ma ieri ho corrò. Fui al banco. È c’è. Cosa sta?”);
for t in doc:
orig = t.text
lemma = lemmatize_contestualmente(t)
print(f”{orig} → {lemma}”)
:
Il corro → corro (base)
corrò → corrò (passato prossimo)
fui → fui
sono → sono
c’è → ci è (gestione morfema complesso)
cosa → cosa
banco → banco
Tavola comparativa: lemmatizzazione vs forma originale con contesto morfologico
| Forma | POS | Lemma | Contesto critico |
|————-|————|————-|——————————–|
| corro | VERB | corro | Primo persona sing. passato prossimo |
| corrò | VERB | corrò | Passato prossimo con “domani” |
| fui | VERB | fui | Passato lontano, contesto temporale chiaro |
| sono | AUX | sono | Ausiliare in frasi negative |
| c’è | DET | ci è | Ellissi pronominale, contesto fluido |
| cosa | NOME | cosa | Nessuna ambiguità alta |
“La lemmatizzazione contestuale salva il modello da ambiguità sintattiche profonde, soprattutto con verbi come ‘corrò’ che in contesti diversi assumono letture morfologiche diverse.”
4. Fase 3: Filtraggio e riduzione del rumore linguistico con regole precise
Il filtraggio di stopword non si limita a “che”, “di”, “è”, ma include termini a bassa rilevanza contestuale come “quello” → “QS” (contesto discorsivo limitato), “su” → “SUP” (preposizione debole).
`spaCy` fornisce liste dinamiche di stopword italiane aggiornate; integrare con regole personalizzate per dialetti: ad esempio, “casa” in Veneto può diventare “casà” senza correzione, ma “c’è” è sempre “ci è”.
Esempio di filtraggio avanzato con analisi dipendenza:
for token in doc:
if token.text.lower() in {“quello”, “quella”, “quelli”, “quelle”} and token.dep_ == “compound” and any(c.dep_ == “nsubj” for c in token.
