spaCy per dati PII: riconoscimento e anonimizzazione dei testi

Immagine di copertina

Quando si lavora con testi che contengono dati sensibili, una delle operazioni più comuni è l’identificazione e la gestione delle informazioni personalmente identificabili (in inglese, Personally Identifiable Information, abbreviato in PII). Si tratta di tutte quelle informazioni che permettono di risalire all’identità di una persona: nomi, indirizzi, numeri di telefono, indirizzi email, codici fiscali e molto altro.

In questo articolo vedremo come sfruttare spaCy, una delle librerie NLP più diffuse in Python, per individuare e gestire queste informazioni all’interno di un testo.

Cosa vedrai

Cosa sono le PII

Le PII includono qualsiasi informazione che, da sola o in combinazione con altri dati, può identificare univocamente una persona. Alcune categorie comuni sono:

  • Dati anagrafici: nome, cognome, data di nascita
  • Dati di contatto: numero di telefono, indirizzo email, indirizzo fisico
  • Documenti di identità: codice fiscale, numero di passaporto, numero di carta d’identità
  • Dati finanziari: IBAN, numero di carta di credito
  • Identificatori digitali: indirizzo IP, username

Il rispetto delle normative come il GDPR impone alle organizzazioni di trattare questi dati con la massima attenzione: spesso è necessario anonimizzarli o pseudonimizzarli prima di poterli utilizzare in sistemi di analisi, log o dataset di addestramento.

Riconoscimento PII con spaCy

spaCy riconosce nativamente alcune entità che corrispondono a categorie PII, tramite il componente NER (Named Entity Recognition). Tra le entità riconoscibili troviamo:

LabelDescrizione
PERSONNomi di persone
ORGOrganizzazioni e aziende
GPELuoghi geopolitici (città, paesi)
LOCLuoghi fisici
DATEDate e periodi temporali
MONEYValori monetari

Per iniziare, installiamo spaCy e il modello per la lingua italiana (o inglese):

pip install spacy
python -m spacy download it_core_news_lg
# oppure per l'inglese:
python -m spacy download en_core_web_lg

Carichiamo il modello e analizziamo un testo di esempio:

import spacy

nlp = spacy.load("it_core_news_lg")

testo = """
Mario Rossi abita in Via Roma 12, Milano. Puoi contattarlo all'indirizzo mario.rossi@email.com 
oppure al numero 333-1234567. Il suo codice fiscale è RSSMRA80A01F205X.
"""

doc = nlp(testo)

print("Entità rilevate:")
for ent in doc.ents:
    print(f"  Testo: {ent.text!r:30s}  Label: {ent.label_}")

L’output mostrerà le entità riconosciute dal modello. Da notare che le entità come email, numeri di telefono e codice fiscale non vengono riconosciute nativamente da spaCy: occorre aggiungere dei matcher personalizzati.

Anonimizzare le entità rilevate

Una volta identificate le entità, è possibile sostituirle con segnaposti generici, mantenendo la struttura del testo ma rimuovendo le informazioni sensibili:

import spacy

nlp = spacy.load("it_core_news_lg")

def anonimizza_testo(testo: str, label_da_anonimizzare: list[str]) -> str:
    """Sostituisce le entità PII con un segnaposto generico."""
    doc = nlp(testo)
    testo_anonimizzato = testo
    # Sostituisco dal fondo per non alterare gli indici
    for ent in reversed(doc.ents):
        if ent.label_ in label_da_anonimizzare:
            segnaposto = f"[{ent.label_}]"
            testo_anonimizzato = (
                testo_anonimizzato[: ent.start_char]
                + segnaposto
                + testo_anonimizzato[ent.end_char :]
            )
    return testo_anonimizzato


testo = "Luca Ferrari lavora per Acme S.p.A. a Roma dal 2019."
label_pii = ["PERSON", "ORG", "GPE", "DATE"]

risultato = anonimizza_testo(testo, label_pii)
print(risultato)
# Output: "[PERSON] lavora per [ORG] a [GPE] dal [DATE]."

Creare un riconoscitore personalizzato

Per individuare entità come email, numeri di telefono o codici fiscali, possiamo usare il componente Matcher (per pattern linguistici) o il PhraseMatcher, oppure il più potente EntityRuler che supporta anche espressioni regolari tramite re.

Ecco come aggiungere un matcher basato su regex per rilevare indirizzi email e codici fiscali italiani:

import re
import spacy
from spacy.language import Language
from spacy.tokens import Span

nlp = spacy.load("it_core_news_lg")

PATTERN_PII = {
    "EMAIL":        r"[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}",
    "TELEFONO":     r"(?:\+39\s?)?(?:0\d{1,4}[\s\-]?\d{4,8}|3\d{2}[\s\-]?\d{6,7})",
    "CODICE_FISCALE": r"\b[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z]\b",
    "IBAN":         r"\b[A-Z]{2}\d{2}[A-Z0-9]{11,27}\b",
}


@Language.component("pii_regex_detector")
def pii_regex_detector(doc):
    """Componente custom che aggiunge entità PII tramite regex."""
    nuove_entita = list(doc.ents)
    for label, pattern in PATTERN_PII.items():
        for match in re.finditer(pattern, doc.text):
            start_char, end_char = match.start(), match.end()
            span = doc.char_span(start_char, end_char, label=label)
            if span is not None:
                nuove_entita.append(span)
    # Filtro eventuali sovrapposizioni
    doc.ents = spacy.util.filter_spans(nuove_entita)
    return doc


# Aggiungo il componente alla pipeline dopo il NER nativo
nlp.add_pipe("pii_regex_detector", last=True)

testo = (
    "Contatta Giulia Bianchi all'indirizzo giulia.bianchi@azienda.it "
    "oppure al 333-9876543. Il suo CF è BNCGLI85M41H501Z."
)

doc = nlp(testo)
for ent in doc.ents:
    print(f"{ent.label_:20s}{ent.text!r}")

Output atteso:

PERSON               → 'Giulia Bianchi'
EMAIL                → 'giulia.bianchi@azienda.it'
TELEFONO             → '333-9876543'
CODICE_FISCALE       → 'BNCGLI85M41H501Z'

Visualizzare i risultati

spaCy include la libreria displaCy, che permette di visualizzare le entità rilevate direttamente nel browser o in un notebook Jupyter:

from spacy import displacy

# In un notebook Jupyter
displacy.render(doc, style="ent", jupyter=True)

# Oppure avvia un server locale
displacy.serve(doc, style="ent")

Il risultato è un’interfaccia visiva che evidenzia le entità con colori diversi a seconda della label assegnata: molto utile per verificare la qualità del riconoscimento e identificare eventuali falsi positivi o negativi.


Nota: spaCy da solo copre una parte delle entità PII. Per un sistema più completo, è possibile integrarlo con librerie dedicate come Microsoft Presidio, che combina spaCy con regole e validatori aggiuntivi per oltre 50 tipi di PII in più lingue.

Risorse utili

Conosci meglio chi ha scritto questo articolo

Serena Sensini

Ciao! Mi chiamo Serena Sensini e sono la creatrice di @ TheRedCode.it. Ho aperto questo blog nel 2021 per raccontare il mio lavoro e il mondo dell’informatica a parole semplici, in piccole pillole e alla portata di tutte le persone.

Sono un’ingegnera informatica specializzata in ambito AI & NLP. Di giorno lavoro come CTO @ Welyk e come Innovation & Emerging Technologies Leader @ Dedalus, mentre di notte scrivo e sono autrice di 5 libri -per ora-. 🖊️

Foto di Serena Sensini

Partners

Community, aziende e persone che supportano attivamente il blog

Vuoi diventare partner?

Collaboriamo con community, aziende e strumenti del mondo tech che vogliono raggiungere la nostra community di dev ed engineer italiani. Scrivici per proporre una collaborazione.

Vuoi diventare tech content creator? 🖊️

Se ti va di raccontare la tua esperienza nel mondo tech, questo è il posto giusto.

Cerchiamo voci autentiche, esempi pratici e punti di vista utili per chi legge.

Scrivici a collaborazioni[at]theredcode.it con una proposta: idea, taglio del contenuto e una breve presentazione. Non vediamo l'ora di leggere la tua esperienza!

Invia la tua idea