Modello Bag of Words in Python: Una Guida Completa

La Busta di Parole (BoW) è una tecnica nel campo del Processamento del Linguaggio Naturale (NLP). È ampiamente utilizzata per trasformare i dati testuali in un formato leggibile dalle macchine, specificamente valori numerici, senza considerare la grammatica e l’ordine delle parole. Comprendere la BoW è importante per chiunque lavora con dati testuali. Python fornisce più strumenti e librerie per implementare efficacemente la Busta di Parole.

In questo tutorial, esploreremo la BoW, introdurremo i suoi concetti, copriremo le sue applicazioni e analizzeremo un’implementazione dettagliata in Python. Alla fine di questo tutorial, sarete in grado di applicare il modello della Busta di Parole a problemi reali. Se siete nuovi nel campo del NLP, date un’occhiata al nostro percorso di competenze in Processamento del Linguaggio Naturale in Python per saperne di più.

Cosa è la Busta di Parole?

La tecnica del Bag of Words è utilizzata per estrarre caratteristiche dai dati testuali per compiti di apprendimento automatico, come la classificazione del testo e l’analisi del sentiment. Questo è importante perché gli algoritmi di apprendimento automatico non possono processare dati testuali. Il processo di conversione del testo in numeri è noto come estrazione delle caratteristiche o codifica delle caratteristiche.

Un Bag of Words si basa sulla presenza di parole in un documento. Il processo inizia con la ricerca del lessico nel testo e la misurazione della loro occorrenza. È chiamato bag perché l’ordine e la struttura delle parole non vengono considerati, solo la loro occorrenza.

Il modello Bag of Words è diverso dal Continuous Bag of Words Model (CBOW), che impara rappresentazioni dense di parole utilizzando le parole circostanti per prevedere una parola target, catturando le relazioni semantiche tra le parole. Il CBOW richiede un addestramento su un ampio corpus e produce vettori a bassa dimensionalità che sono preziosi per applicazioni di NLP complesse dove il contesto della parola è importante.

Aspetto

BOW

CBOW

Scopo

Conta le occorrenze di ogni parola

Predice la parola target in base al contesto

Tipo di Output

Vettore ad alta dimensionalità, sparsamente popolato

Vettore a bassa dimensionalità, denso

Considera il Contesto

No (ignora l’ordine delle parole)

Sì (utilizza le parole circostanti)

Rappresentazione

Vettore di frequenza sparsamente popolato

Vettore denso che cattura la semantica

Complessità

Basso (nessun addestramento richiesto)

Alto (richiede addestramento su un ampio corpus)

Applicazioni tipiche

Classificazione del testo, analisi del sentiment

Word embeddings, compiti di NLP che richiedono contesto

Perché usare Bag of Words?

Bag of Words è utile in molte compiti di NLP, alcuni motivi per il suo utilizzo includono:

  • Estrazione delle caratteristiche: Converte dati testuali non strutturati in dati strutturati, che possono essere utilizzati come input per vari algoritmi di apprendimento automatico.
  • Semplicità ed efficienza: BoW è computazionalmente semplice da implementare e funziona bene per piccoli e medi corpus testuali.
  • Similarità tra documenti: Può essere utilizzato per calcolare la similarità tra documenti testuali utilizzando tecniche come la similarità del coseno.
  • Classificazione del testo: Quando combinato con tecniche come Naive Bayes, BoW è efficace per compiti di classificazione del testo come la classificazione dello spam, e analisi del sentiment.

Tuttavia, ci sono anche svantaggi, come la mancanza di considerazione della semantica, della struttura delle parole o dell’ordine delle parole.

Passi per Implementare Bag of Words in Python

Per creare un modello bag-of-words, prendiamo tutte le parole in un corpus e creiamo una colonna con ciascuna parola. Le righe rappresentano le frasi. Se una certa parola esiste nella frase, viene rappresentata da un 1, e se la parola non esiste, viene rappresentata da uno 0. Ogni parola nella colonna rappresenta una singola caratteristica.

Alla fine otteniamo una matrice sparsa. Una matrice sparsa è una matrice con molti zeri.

Preelaborazione dei dati

Per creare un modello Bag of Words in Python, è necessario seguire alcuni passaggi di preelaborazione. Questi passaggi includono la tokenizzazione e la rimozione delle stopwords.

La tokenizzazione è il processo di suddividere un pezzo di testo in unità più piccole, tipicamente parole. Puoi eseguire la tokenizzazione utilizzando NLTK

Le parole vuote sono parole comuni in inglese, come “the,” “that,” e “a,” che non contribuiscono alla polarità di una frase.

import nltk from nltk.corpus import stopwords from nltk.tokenize import word_tokenize Scarica stopwords e tokenizer se non l'hai già fatto nltk.download("punkt") nltk.download("stopwords") Esempio di frase sentence = "This is an example showing how to remove stop words from a sentence." Tokenizza la frase in parole words = word_tokenize(sentence) Ottieni l'elenco delle parole vuote in inglese stop_words = set(stopwords.words("english")) Rimuovi le parole vuote dalla frase filtered_sentence = [word for word in words if word.lower() not in stop_words] Unisci le parole di nuovo in una frase filtered_sentence = " ".join(filtered_sentence) print(filtered_sentence)

Output:

example showing remove stop words sentence.

Creazione di un lessico

Un lessico è una raccolta di parole uniche trovate in un corpus di testi. Costruire un lessico implica raccogliere tutte le parole uniche dal corpus e contare le loro occorrenze. Questo lessico è utile per vari compiti di NLP come modellazione del linguaggio, word embeddings e classificazione del testo.

Il codice qui sotto crea una semplice distribuzione di frequenza delle parole nel corpus, utile per compiti di NLP di base come costruire un lessico o comprendere il contenuto del testo:

  • Il corpus variabile contiene alcune frasi di esempio. In applicazioni reali, questa conterrà dati testuali più ampi e variati.
  • vocab = defaultdict(int) semplifica il conteggio della frequenza delle parole, inizializzando automaticamente qualsiasi nuova parola con un conteggio di 0, permettendo di incrementare direttamente senza controlli.
  • Ogni frase viene tokenizzata convertendola in minuscolo ed estraendo le parole utilizzando espressioni regolari. Il modello \b\w+\b identifica parole con caratteri alfanumerici solo, ignorando la punteggiatura ed altri simboli.
  • Il conteggio di ogni parola viene aggiornato nel vocab dizionario.
  • Il vocabolario è ordinato per frequenza in ordine decrescente, rendendo facile vedere le parole più comuni in cima, ed è visualizzato per riferimento.
import re Importa il modulo delle espressioni regolari per aiutare con l'elaborazione del testo from collections import ( defaultdict, ) Importa defaultdict per gestire facilmente il conteggio della frequenza delle parole Corpus di testo di esempio - un piccolo set di dati di frasi da analizzare corpus = [ "Tokenization is the process of breaking text into words.", "Vocabulary is the collection of unique words.", "The process of tokenizing is essential in NLP.", ] Inizializza un defaultdict con valori interi per memorizzare le frequenze delle parole defaultdict(int) inizializza ogni nuova chiave con un valore intero predefinito di 0 vocab = defaultdict(int) Cicla attraverso ogni frase nel corpus per tokenizzare e normalizzare for sentence in corpus: Converti la frase in minuscolo per garantire coerenza nel conteggio (ad esempio, 'Tokenization' e 'tokenization' vengono trattate come la stessa parola) Utilizza espressioni regolari per trovare parole composte solo da caratteri alfanumerici words = re.findall(r"\b\w+\b", sentence.lower()) Per ogni parola trovata, incrementa il suo conteggio nel dizionario vocab for word in words: vocab[word] += 1 Converti il defaultdict vocab in un dizionario regolare per una gestione e ordinamento più facile Ordina il dizionario per frequenza delle parole in ordine discendente e convertilo in un nuovo dizionario sorted_vocab = dict(sorted(vocab.items(), key=lambda x: x[1], reverse=True)) Visualizza il lessico ordinato con ogni parola e il suo conteggio di frequenza print("Vocabulary with Frequencies:", sorted_vocab)

Output:

Vocabulary with Frequencies: {'is': 3, 'the': 3, 'of': 3, 'process': 2, 'words': 2, 'tokenization': 1, 'breaking': 1, 'text': 1, 'into': 1, 'vocabulary': 1, 'collection': 1, 'unique': 1, 'tokenizing': 1, 'essential': 1, 'in': 1, 'nlp': 1}

Costruire manualmente un vocabolario può essere dispendioso in termini di tempo, specialmente per grandi corpora. CountVectorizer di Scikit-learn automatizza questo processo e permette una gestione del testo più flessibile, come vedremo in seguito.

Implementazione del Bag of Words Utilizzando Python (Dal Scratch)

Iniziamo con una semplice implementazione del Bag of Words dallo zero in Python. Questo vi aiuterà a comprendere i componenti fondamentali e la meccanica di come funziona sotto il cofano.

Implementazione manuale

Passo 1: Preelaborazione dei Dati Testuali

Inizieremo definendo una semplice funzione per processare il testo, inclusa la tokenizzazione, la conversione in minuscolo e la rimozione della punteggiatura.

from collections import defaultdict import string # Dati testuali di esempio: frasi corpus = [ "Python is amazing and fun.", "Python is not just fun but also powerful.", "Learning Python is fun!", ] # Funzione per preelaborare il testo def preprocess(text): # Converti in minuscolo text = text.lower() # Rimuovi la punteggiatura text = text.translate(str.maketrans("", "", string.punctuation)) # Tokenizza: suddividi il testo in parole tokens = text.split() return tokens # Applica la preelaborazione al corpus di esempio processed_corpus = [preprocess(sentence) for sentence in corpus] print(processed_corpus)

Output:

[['python', 'is', 'amazing', 'and', 'fun'], ['python', 'is', 'not', 'just', 'fun', 'but', 'also', 'powerful'], ['learning', 'python', 'is', 'fun']]

Passo 2: Costruzione del Vocabolario

Ora, dobbiamo scansionare tutti i documenti e costruire un elenco completo di parole uniche, ossia il nostro vocabolario.

Inizializza un set vuoto per il vocabolario vocabulary = set() Costruisci il vocabolario for sentence in processed_corpus: vocabulary.update(sentence) Converti in una lista ordinata vocabulary = sorted(list(vocabulary)) print("Vocabulary:", vocabulary)

Step 3: Calcola le Frequenze delle Parole e Vettorizza

Calcoleremo ora la frequenza di ogni parola nel vocabolario per ogni documento nel corpus elaborato.

def create_bow_vector(sentence, vocab): vector = [0] * len(vocab) Inizializza un vettore di zeri for word in sentence: if word in vocab: idx = vocab.index(word) Trova l'indice della parola nel vocabolario vector[idx] += 1 Incrementa il conteggio a quell'indice return vector

A questo punto, avrai creato una rappresentazione Bag of Words per ogni documento nel tuo corpus.

Crea un vettore BoW per ogni frase nel corpus elaborato bow_vectors = [create_bow_vector(sentence, vocabulary) for sentence in processed_corpus] print("Bag of Words Vectors:") for vector in bow_vectors: print(vector)

Output:

Bag of Words Vectors: [0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1] [1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1] [0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1]

Utilizzando CountVectorizer di Scikit-learn

Costruire un modello di Bag of Words manualmente è utile per imparare, ma per applicazioni di produzione, vorrai utilizzare librerie efficienti e ottimizzate come Scikit-learn.

La funzione Python che utilizziamo per la tokenizzazione è CountVectorizer, che è importata da sklearn.feature_extraction.text. Una delle caratteristiche di CountVectorizer è max_features, che rappresenta il numero massimo di parole che si desidera avere nel modello della borsa delle parole. In questo caso, utilizziamo None, il che significa che saranno utilizzate tutte le caratteristiche. 

Dopo aver creato un’istanza di CountVectorizer, utilizzare il metodo .fit_transform() per creare il modello della borsa delle parole. Successivamente, utilizzare .toarray() per convertire il modello della borsa delle parole in array numpy che possono essere alimentati a un modello di machine learning.

Dopo l’installazione, CountVectorizer ha costruito un dizionario degli indici delle caratteristiche. Il valore dell’indice di una parola nel vocabolario è collegato alla sua frequenza nell’intero corpus di addestramento.

from sklearn.feature_extraction.text import CountVectorizer # Corpus originale corpus = [ "Python is amazing and fun.", "Python is not just fun but also powerful.", "Learning Python is fun!", ] # Creare un oggetto CountVectorizer vectorizer = CountVectorizer() # Adattare e trasformare il corpus X = vectorizer.fit_transform(corpus) # Stampare il vocabolario generato print("Vocabulary:", vectorizer.get_feature_names_out()) # Stampare la matrice Bag-of-Words print("BoW Representation:") print(X.toarray())

Output:

markdownVocabulary: ['also' 'amazing' 'and' 'but' 'fun' 'is' 'just' 'learning' 'not' 'powerful' 'python'] BoW Representation: [[0 1 1 0 1 1 0 0 0 0 1] [1 0 0 1 1 1 1 0 1 1 1] [0 0 0 0 1 1 0 1 0 0 1]]

Esempio: Applicazione del Bag of Words

Adesso applichiamo il modello BoW a un piccolo corpus testuale costituito da tre recensioni di film per illustrare l’intero processo. 

Utilizzeremo CountVectorizer di Scikit-learn per applicare il modello BoW a questo piccolo corpus testuale.

Ecco i passaggi che seguiranno:

  • CountVectorizer tokenizza il testo, rimuove la punteggiatura e converte automaticamente le parole in minuscolo.
  • .fit_transform(corpus) converte il corpus in una matrice documento-termine, dove ogni riga rappresenta un documento e ogni colonna rappresenta una parola del lessico.
  • X_dense è la matrice densa che rappresenta la frequenza di ogni parola in ogni documento.
from sklearn.feature_extraction.text import CountVectorizer # Corpus di esempio di recensioni di film corpus = [ "I loved the movie, it was fantastic!", "The movie was okay, but not great.", "I hated the movie, it was terrible.", ] # Inizializzare il CountVectorizer vectorizer = CountVectorizer() # Adattare e trasformare il corpus in una matrice documento-termine X = vectorizer.fit_transform(corpus) # Convertire la matrice documento-termine in un formato denso (opzionale per la visualizzazione) X_dense = X.toarray() # Ottenere il lessico (mappatura delle parole alle posizioni degli indici) vocab = vectorizer.get_feature_names_out() # Stampare il lessico e la matrice documento-termine print("Vocabulary:", vocab) print("Document-Term Matrix:\n", X_dense)

Output:

Vocabulary: ['but' 'fantastic' 'great' 'hated' 'it' 'loved' 'movie' 'not' 'okay' 'terrible' 'the' 'was'] Document-Term Matrix: [[0 1 0 0 1 1 1 0 0 0 1 1] Prima recensione: "Adoravo il film, era fantastico!" [1 0 1 0 1 0 1 1 1 0 1 1] Seconda recensione: "Il film era discreto, ma non eccezionale." [0 0 0 1 1 0 1 0 0 1 1 1]] Terza recensione: "Odiavo il film, era orribile."

Ecco come possiamo interpretare l’output sopra:

  • Ogni parola unica nel corpus viene assegnata a un indice, e le parole sono ordinate alfabeticamente. Per esempio, “but” è all’indice 0, “fantastic” è all’indice 1, “movie” è all’indice 6, e così via.
  • Ogni riga nella matrice del documento rappresenta una recensione del film, e ogni colonna corrisponde a una parola del lessico. I valori nella matrice rappresentano la frequenza di ogni parola in quel documento specifico.
    • Prima recensione: [0 1 0 0 1 1 1 0 0 0 1 1] indica che:
      • La parola “fantastic” compare una volta (1 all’indice 1),
      • La parola “adoravo” compare una volta (1 all’indice 5),
      • La parola “film” compare una volta (1 all’indice 6),
      • La parola “era” compare una volta (1 all’indice 4),
      • E così via.

Il vettore BoW può essere interpretato come segue:

  • Ogni documento è un vettore di numeri che rappresentano i conteggi delle parole. Le dimensioni del vettore sono uguali alla dimensione del lessico. In questo caso, il lessico ha 12 parole, quindi ogni recensione viene trasformata in un vettore 12-dimensionale.
  • Molte parole in ogni riga sono zero perché non ogni documento contiene tutte le parole del lessico. Pertanto, i modelli BoW sono spesso sparsi, cioè hanno molti zeri.

Vantaggi e Limitazioni del Modello Bag of Words

Lasciamo ora esaminare alcuni dei vantaggi e delle limitazioni del modello Bag of Words.

Vantaggi

  1. Semplice da implementare e interpretare: Il modello Bag of Words è una delle tecniche di rappresentazione del testo più semplici, rendendolo ideale per i principianti. La sua semplicità permette una rapida implementazione senza la necessità di preprocessing complesso o modelli specializzati.
  2. Facile da utilizzare per compiti di classificazione del testo: Bag of Words è adatto per compiti di base come la classificazione del testo, l’analisi del sentiment e la rilevazione dello spam. Questi compiti spesso non richiedono modelli linguistici sofisticati, quindi una rappresentazione BOW è sufficiente ed efficiente.

Limitazioni

  1. La dimensione del vocabolario influisce sulla sparsità delle rappresentazioni: Più grande è il vocabolario, più sparsa e ad alta dimensionalità diventa la rappresentazione. Questa sparsità può rendere più difficile per i modelli imparare efficacemente e richiede un’attenta regolazione della dimensione del vocabolario per evitare costi computazionali eccessivi.
  2. Produce matrici sparse che sono computazionalmente costose: Poiché ciascun documento è rappresentato dalla frequenza di ciascuna parola in un vocabolario potenzialmente grande, le matrici resulting sono spesso perlopiù formate da zeri, il che può essere inefficiente da memorizzare e processare nelle pipeline di machine learning. Le matrici sparse consumano molta memoria e spesso richiedono strumenti e librerie specializzate per un’efficiente memorizzazione e computazione, specialmente con grandi set di dati.
  3. Perde significato e contesto: BOW trascura l’ordine delle parole e la struttura della frase, il che porta alla perdita di relazioni grammaticali e significato. Questa limitazione lo rende meno adatto per compiti dove il contesto, le sfumature e l’ordine delle parole sono importanti, come la traduzione o il rilevamento del sentiment in frasi complesse.

Le seguenti strategie possono essere utilizzate per ridurre la dimensione del vocabolario nel Bag of Words:

  • Ignorare le maiuscole.
  • Removere la punteggiatura.
  • Removere stopwords, ovvero parole comuni come “the” e “a”.
  • Assicurarsi che tutte le parole siano correttamente scritte.
  • Utilizzare tecniche di stemming per ridurre le parole alla loro forma radice.

Prossimi passi: Oltre il Bag of Words

Una limitazione del modello Bag of Words è che tratta tutte le parole in modo uguale. Purtroppo, questo può portare a problemi dove alcune parole vengono date più importanza semplicemente perché appaiono frequentemente.

TF-IDF (Term Frequency-Inverse Document Frequency) è una soluzione a questo problema, poiché aggiusta il peso delle parole in base a quanto frequentemente esse appaiono in tutti i documenti.

TF-IDF: Un’estensione del Bag of Words

La Frequenza del Termine (TF) rappresenta la frequenza di un termine in un documento. La Frequenza Inversa del Documento (IDF) riduce l’impatto delle parole comunemente occurring in più documenti. Il punteggio TF-IDF è calcolato moltiplicando le due metriche.

Consideriamo un documento contenente 200 parole, dove la parola amore compare 5 volte. Il TF per amore è quindi (5 / 200) = 0,025. Supponiamo di avere un milione di documenti e che la parola amore compaia in mille di questi, l’inverse document frequency (ovvero, IDF) viene calcolata come log(1000000 / 1000) = 3. Il peso TF-IDF è il prodotto di queste quantità: 0,025 * 3 = 0,075.

In Scikit-learn, questo è relativamente facile da calcolare utilizzando la classe TfidfVectorizer.

from sklearn.feature_extraction.text import TfidfVectorizer # Corpus di esempio corpus = [ "Python is amazing and fun.", "Python is not just fun but also powerful.", "Learning Python is fun!", ] # Creare il vettore di Tf-idf tfidf_vectorizer = TfidfVectorizer() # Adattare e trasformare il corpus X_tfidf = tfidf_vectorizer.fit_transform(corpus) # Mostrare il lessico print("Vocabulary:", tfidf_vectorizer.get_feature_names_out()) # Mostrare la Matrice TF-IDF print("TF-IDF Representation:") print(X_tfidf.toarray())

Output:

Vocabulary: ['also' 'amazing' 'and' 'but' 'fun' 'is' 'just' 'learning' 'not' 'powerful' 'python'] TF-IDF Representation: [[0. 0.57292883 0.57292883 0. 0.338381 0.338381 0. 0. 0. 0. 0.338381 ] [0.40667606 0. 0. 0.40667606 0.24018943 0.24018943 0.40667606 0. 0.40667606 0.40667606 0.24018943] [0. 0. 0. 0. 0.41285857 0.41285857 0. 0.69903033 0. 0. 0.41285857]]

La matrice TF-IDF implementata in alto ti fornisce una misura pesata invece di frequenze grezze.

Mentre il modello del Bag of Words ha le sue limitazioni, specialmente per dataset più grandi e complessi, è tuttavia un blocco costruttivo essenziale in molte applicazioni di NLP. Capirlo ti aiuterà quando esplorerai modelli più avanzati come word embeddings e Transformers.

Da qui, potresti sperimentare con BoW nei tuoi progetti, inclusi spam detection, sentiment analysis, clustering di documenti e altro.

Se vuoi ulteriori miglioramenti oltre al Bag of Words, puoi esplorare metodi come Word2Vec e GloVe, o modelli di deep learning come BERT.

Pensieri finali

La tecnica del Bag of Words è una tecnica fondamentale utilizzata nel Processamento del Linguaggio Naturale. Serve come un modo semplice ma efficace per convertire testi non strutturati in caratteristiche numeriche utilizzabili dagli algoritmi di machine learning. In questo tutorial, abbiamo coperto:

  • Cosa è il modello Bag of Words (BoW)?
  • I vantaggi del modello Bag of Word nella costruzione di modelli di machine learning.
  • Come implementare il modello Bag of Words in Python.
  • Vantaggi e limitazioni del Bag of Words.
  • La teoria e la motivazione dietro il modello Bag of Words.
  • Introduzione del TF-IDF come miglioramento rispetto all’approccio tradizionale del Bag of Words.

Scopri il nostro skill track di Natural Language Processing in Python, per addentrarti nel processing del linguaggio naturale.

Source:
https://www.datacamp.com/tutorial/python-bag-of-words-model