Bag of Words (BoW) is een techniek in de Natuurlijke Taalverwerking (NLP). Het wordt breed toegepast om tekstgegevens om te zetten in machinaal leesbaar formaat, specifiek numerieke waarden, zonder rekening te houden met grammatica en woordvolgorde. Begrijpen van BoW is belangrijk voor iedereen die werkt met tekstgegevens. Python biedt meerdere hulpmiddelen en bibliotheken om Bag of Words effectief te implementeren.
In deze handleiding duiken we diep in BoW, introduceren we de concepten, bespreken we de toepassingen en lopen we door een gedetailleerde implementatie in Python. Aan het einde van deze handleiding kun je het Bag of Words-model toepassen op praktische problemen. Als je nieuw bent in NLP, bekijk dan onze Natural Language Processing in Python skill track om meer te leren.
Wat is Bag of Words?
Bag of Words is een techniek voor het extraheren van kenmerken uit tekstgegevens voor machinaallerende taken, zoals tekstclassificatie en sentimentanalyse. Dit is belangrijk omdat machinaallerende algoritmen tekstuele gegevens niet kunnen verwerken. Het proces van het omzetten van tekst naar getallen staat bekend als kenmerkextractie of kenmerkencodering.
Een Bag of Words is gebaseerd op de aanwezigheid van woorden in een document. Het proces begint met het vinden van de woordenschat in de tekst en het meten van hun voorkomen. Het wordt een ‘bag’ genoemd omdat de volgorde en structuur van de woorden niet worden overwogen, alleen hun voorkomen.
Het Bag of Words-model verschilt van het Continuous Bag of Words Model (CBOW), dat dichtheidswoordvectoren leert door gebruik te maken van omliggende woorden om een doelwoord te voorspellen, en zo semantische relaties tussen woorden vastlegt. CBOW vereist training op een groot corpus en produceert lage-dimensionale vectoren die waardevol zijn voor complexe NLP-toepassingen waar de context van woorden belangrijk is.
Aspect |
BOW |
CBOW |
Doel |
Telt het aantal keer dat elk woord voorkomt |
Voorspelt het doelwoord op basis van de context |
Output Type |
Hoge dimensie, spaarzaam vector |
Lage dimensie, dich vector |
Overweegt Context |
Nee (negeert woordvolgorde) |
Ja (gebruikt omliggende woorden) |
Representatie |
Sparse frequentievector |
Dense vector die semantiek vastlegt |
Complexiteit |
Laag (geen training vereist) |
Hoog (vereist training op grote corpus) |
Typische Toepassingen |
Textclassificatie, sentimentanalyse |
Woordenimboddingen, NLP-taken die context vereisen |
Waarom Bag of Words Gebruiken?
Bag of Words is nuttig in veel NLP-taken, enkele redenen voor zijn gebruik zijn:
- Feature extractie: Het omzetten van gestructureerde tekstgegevens naar gestructureerde gegevens, die kunnen worden gebruikt als invoer voor verschillende machine learning-algoritmen.
- Simpelheid en efficiëntie: BoW is computationally eenvoudig uit te voeren en werkt goed voor kleine tot middelgrote tekstcorpora.
- Documentvergelijkbaarheid: Het kan worden gebruikt om de vergelijkbaarheid tussen tekst-documenten te berekenen met technieken zoals cosinesimilarity.
- Tekstclassificatie: Wanneer gecombineerd met technieken zoals Naive Bayes, is BoW effectief voor tekstclassificatietaken zoals spamclassificatie, en sentimentanalyse.
Echter, er zijn ook nadelen, zoals het niet overwegen van semantiek, woordstructuur of woordvolgorde.
Stappen om Bag of Words in Python te implementeren
Om een woordenbakmodel te maken, nemen we alle woorden in een corpus en maken we een kolom met elk woord. De rijen vertegenwoordigen de zinnen. Als een bepaald woord voorkomt in de zin, wordt het vertegenwoordigd door een 1, en als het woord niet voorkomt, wordt het vertegenwoordigd door een 0. Elk woord in de kolom vertegenwoordigt een enkele kenmerk.
Aan het einde verkrijgen we een sparese matrix. Een sparese matrix is een matrix met veel nullen.
Gegevens Voorverwerking
Om een Woordenbakmodel te maken in Python, moeten we een paar voorverwerkingsslagen doorlopen. Deze stappen omvatten tokenisatie en het verwijderen van stopwoorden.
.
Tokenisatie is het proces van het opsplitsen van een stuk tekst in kleinere eenheden, meestal woorden. Je kunt tokenisatie uitvoeren met NLTK.
Stopwoorden zijn veelvoorkomende woorden in het Engels, zoals “the,” “that,” en “a,” die geen bijdrage leveren aan de polariteit van een zin.
import nltk from nltk.corpus import stopwords from nltk.tokenize import word_tokenize # Download stopwords en tokenizer als je die nog niet hebt gedownload nltk.download("punkt") nltk.download("stopwords") # Voorbeeldzin sentence = "This is an example showing how to remove stop words from a sentence." # Ver deel de zin in woorden words = word_tokenize(sentence) # Verkrijg de lijst van stopwoorden in het Engels stop_words = set(stopwords.words("english")) # Verwijder stopwoorden uit de zin filtered_sentence = [word for word in words if word.lower() not in stop_words] # Voeg de woorden weer samen tot een zin filtered_sentence = " ".join(filtered_sentence) print(filtered_sentence)
Output:
example showing remove stop words sentence.
Creëren van een woordenlijst
Een woordenlijst is een verzameling unieke woorden die worden gevonden in een korpus van tekst. Het opbouwen van een woordenlijst houdt in dat alle unieke woorden uit het korpus worden verzameld en hun voorkomens worden geteld. Deze woordenlijst is nuttig voor verschillende NLP-taken zoals taalmodellering, woordvectoren en tekstclassificatie.
De onderstaande code maakt een eenvoudige frequentieverdeling van woorden in het korpus, nuttig voor basis NLP-taken zoals het bouwen van een woordenlijst of het begrijpen van tekstinhoud:
- De corpus variabele bevat enkele voorbeeldzinnen. In echte toepassingen zou deze grotere, meer gevarieerde tekstgegevens bevatten.
- vocab =
defaultdict(int)
vereenvoudigt het tellen van woordfrequentie, door automatisch nieuwe woorden te initialiseren met een telling van 0, waardoor directe incrementatie zonder controles mogelijk is. - Elke zin wordt getokeniseerd door deze naar kleine letters te converteren en woorden te extraheren met behulp van reguliere expressies. Het patroon
\b\w+\b
identificeert woorden die alleen alfanumerieke tekens bevatten, leestekens en andere symbolen worden genegeerd. - Het aantal van elk woord wordt bijgewerkt in de vocab dictionary.
- De woordenschat wordt gesorteerd op frequentie in aflopende volgorde, zodat de meest voorkomende woorden bovenaan gemakkelijk te zien zijn en wordt weergegeven voor referentie.
import re # Importeer het reguliere expressiesmodule om te helpen bij tekstverwerking from collections import ( defaultdict, ) # Importeer defaultdict om gemakkelijk woordfrequentie tellen te behandelen # Voorbeeld corpus van tekst - een kleine dataset van zinnen om te analyseren 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.", ] # Initialiseer een defaultdict met integerwaarden om woordfrequenties op te slaan # defaultdict(int) initialiseert elke nieuwe sleutel met een standaard integerwaarde van 0 vocab = defaultdict(int) # Loop door elke zin in het corpus om te tokeniseren en te normaliseren for sentence in corpus: # Converteer de zin naar kleine letters om consistentie in telling te waarborgen (bijvoorbeeld, 'Tokenization' en 'tokenization' worden als hetzelfde woord behandeld) # Gebruik reguliere expressies om woorden bestaande uit alleen alfanumerieke tekens te vinden words = re.findall(r"\b\w+\b", sentence.lower()) # Voor elk gevonden woord, verhoog het aantal in het vocab dictionary for word in words: vocab[word] += 1 # Converteer de defaultdict vocab naar een reguliere dictionary voor gemakkelijkere behandeling en sortering # Sorteer de dictionary op woordfrequentie in aflopende volgorde en converteer het naar een nieuwe dictionary sorted_vocab = dict(sorted(vocab.items(), key=lambda x: x[1], reverse=True)) # Toon de gesorteerde woordenschat met elk woord en zijn frequentie teller 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}
Handmatig een woordenschat opbouwen kan tijdrovend zijn, vooral voor grote corpora. Scikit-learn’s CountVectorizer automatiseert dit proces en maakt meer flexibele tekstverwerking mogelijk zoals we later zullen zien.
Bag of Words Implementatie met Python (Vanaf Scratch)
Laten we beginnen met een eenvoudige implementatie van Bag of Words vanaf scratch inPython. Dit zal je helpen de bouwstenen en mechanismen te begrijpen die eraan ten grondslag liggen.
Handmatige implementatie
Stap 1: Voorbewerken van de Tekstgegevens
We beginnen met het definiëren van een eenvoudige functie om tekst te verwerken, inclusief tokenisatie, omzetten naar kleine letters en verwijderen van leestekens.
from collections import defaultdict import string # Voorbeeld tekstgegevens: zinnen corpus = [ "Python is amazing and fun.", "Python is not just fun but also powerful.", "Learning Python is fun!", ] # Functie om tekst voor te bewerken def preprocess(text): # Omzetten naar kleine letters text = text.lower() # Leestekens verwijderen text = text.translate(str.maketrans("", "", string.punctuation)) # Tokeniseren: splits de tekst in woorden tokens = text.split() return tokens # Voorbewerking toepassen op het voorbeeld corpus processed_corpus = [preprocess(sentence) for sentence in corpus] print(processed_corpus)
Uitvoer:
[['python', 'is', 'amazing', 'and', 'fun'], ['python', 'is', 'not', 'just', 'fun', 'but', 'also', 'powerful'], ['learning', 'python', 'is', 'fun']]
Stap 2: Bouw Woordenschat
Nu moeten we door alle documenten scannen en een complete lijst van unieke woorden maken, dat is onze woordenschat.
# Initialiseren van een lege verzameling voor de woordenschat vocabulary = set() # Bouw de woordenschat for sentence in processed_corpus: vocabulary.update(sentence) # Converteer naar een gesorteerde lijst vocabulary = sorted(list(vocabulary)) print("Vocabulary:", vocabulary)
Stap 3: Bereken Woordfrequenties en Vectoriseer
We gaan nu de frequentie van elk woord in de woordenschat berekenen voor elk document in de verwerkte korpus.
def create_bow_vector(sentence, vocab): vector = [0] * len(vocab) # Initialiseer een vector van nullen for word in sentence: if word in vocab: idx = vocab.index(word) # Vind de index van het woord in de woordenschat vector[idx] += 1 # Verhoog het telling op die index return vector
Op dit punt hebt u een Bag of Words-representatie gemaakt voor elk document in uw korpus.
# Maak een BoW-vector voor elke zin in de verwerkte korpus 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]
Gebruik Scikit-learn’s CountVectorizer
Handmatig een Bag of Words-model bouwen is goed voor leren, maar voor productie-applicaties wilt u efficiënte, geoptimaliseerde bibliotheken zoals Scikit-learn gebruiken.
De Python-functie die we gebruiken voor tokenisatie is CountVectorizer, die geïmporteerd wordt vanuit sklearn.feature_extraction.text
. Een van de kenmerken van CountVectorizer
is max_features
, wat het maximale aantal woorden represents dat je wilt hebben in het bag of words-model. In dit geval gebruiken we None, wat betekent dat alle kenmerken zullen worden gebruikt.
Nadat je een instantie van CountVectorizer
hebt gemaakt, gebruik je de .fit_transform(
)-methode om het bag of words-model te maken. Vervolgens gebruik je .toarray()
om het bag of words-model te converteren naar numpy-arrays die aan een machine learning-model kunnen worden gevoed.
Una vez ajustado, CountVectorizer ha construido un diccionario de índices de características. El valor de índice de una palabra en el vocabulario está vinculado a su frecuencia en todo el corpus de entrenamiento.
from sklearn.feature_extraction.text import CountVectorizer # Corpus original corpus = [ "Python is amazing and fun.", "Python is not just fun but also powerful.", "Learning Python is fun!", ] # Crear un objeto CountVectorizer vectorizer = CountVectorizer() # Ajustar y transformar el corpus X = vectorizer.fit_transform(corpus) # Imprimir el vocabulario generado print("Vocabulary:", vectorizer.get_feature_names_out()) # Imprimir la matriz de Bag-of-Words print("BoW Representation:") print(X.toarray())
Salida:
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]]
Ejemplo: Aplicando Bag of Words
Ahora aplicaremos el modelo BoW a un pequeño corpus de texto compuesto por tres reseñas de películas para ilustrar todo el proceso.
Usaremos CountVectorizer de Scikit-learn para aplicar el modelo BoW a este pequeño corpus de texto.
Estos son los pasos que seguiremos:
CountVectorizer
tokeniza el texto, elimina la puntuación y convierte las palabras en minúsculas automáticamente..fit_transform(corpus)
zet het corpus om in een document-term matrix, waar elke rij een document vertegenwoordigt en elke kolom een woord uit het vocabulaire.X_dense
is de dichtheidsmatrix die de frequentie van elk woord in elk document vertegenwoordigt.
from sklearn.feature_extraction.text import CountVectorizer # Voorbeeld corpus van filmrecensies corpus = [ "I loved the movie, it was fantastic!", "The movie was okay, but not great.", "I hated the movie, it was terrible.", ] # Initialiseer de CountVectorizer vectorizer = CountVectorizer() # Pas het corpus toe en transformeer het naar een document-term matrix X = vectorizer.fit_transform(corpus) # Converteer de document-term matrix naar een dichtheidsvorm (optioneel voor visualisatie) X_dense = X.toarray() # Verkrijg het vocabulaire (toewijzing van woorden naar indexposities) vocab = vectorizer.get_feature_names_out() # Print het vocabulaire en de document-term matrix 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] # Eerste beoordeling: "Ik vond de film geweldig, het was fantastisch!" [1 0 1 0 1 0 1 1 1 0 1 1] # Tweede beoordeling: "De film was prima, maar niet geweldig." [0 0 0 1 1 0 1 0 0 1 1 1]] # Derde beoordeling: "Ik haat de film, het was verschrikkelijk."
Hier is hoe we de bovenstaande uitvoer kunnen interpreteren:
- Elk uniek woord in de corpus krijgt een index toegewezen en de woorden worden alfabetisch geordend. Bijvoorbeeld, “maar” is op index 0, “fantastisch” is op index 1, “film” is op index 6, en zo verder.
- Elke rij in de documentenmatrix vertegenwoordigt een filmbespreking, en elke kolom corresponds met een woord uit het vocabulaire. De waarden in de matrix geven de frequentie van elk woord in dat specifieke document weer.
- Eerste beoordeling: [0 1 0 0 1 1 1 0 0 0 1 1] geeft aan dat:
- Het woord “fantastisch” komt een keer voor (1 op index 1),
- Het woord “vond” komt een keer voor (1 op index 5),
- Het woord “film” komt een keer voor (1 op index 6),
- Het woord “het” komt een keer voor (1 op index 4),
- En zo verder.
De BoW-vector kan als volgt worden geïnterpreteerd:
- Elk document is een vector van getallen die woordtellingen vertegenwoordigen. De afmetingen van de vector zijn gelijk aan de grootte van het vocabulaire. In dit geval heeft het vocabulaire 12 woorden, dus elke beoordeling wordt omgezet in een 12-dimensionale vector.
- De meeste woorden in elke rij zijn nullen omdat niet elk document elk woord uit het vocabulaire bevat. Daarom zijn BoW-modellen vaak spaarzaam, dat wil zeggen, ze hebben veel nullen.
Voordelen en Beperkingen van het Bag of Words
Laten we nu enkele voordelen en beperkingen van het Bag of Words-model bespreken.
Voordelen
- Eenvoudig uit te voeren en te interpreteren: Het Bag of Words-model is een van de meest eenvoudige tekstrepresentatietechnieken, waardoor het ideaal is voor beginners. Zijn eenvoud maakt een snelle implementatie mogelijk zonder de noodzaak van complexe voorverwerking of gespecialiseerde modellen.
- Gemakkelijk te gebruiken voor tekstclassificatietaken: Bag of Words is geschikt voor basis taken zoals tekstclassificatie, sentimentanalyse en spamdetectie. Deze taken vereisen vaak geen geavanceerde taalmodellen, dus een BOW-representatie is voldoende en efficiënt.
Beperkingen
- Vocabulairegrootte beïnvloedt de sparsity van representaties: Hoe groter het vocabulaire, hoe sparser en hogerdimensionaal de representatie wordt. Deze sparsity kan het moeilijker maken voor modellen om effectief te leren en vereist zorgvuldige afstemming van de vocabulairegrootte om overmatige computationele kosten te voorkomen.
- Produceert sparse matrices die computationally expensive zijn: Aangezien elk document wordt vertegenwoordigd door de frequentie van elke woord in een mogelijk groot vocabulaire, zijn de resulterende matrices vaak voornamelijk nullen, wat inefficiënt kan zijn om op te slaan en te verwerken in machine learning-pipelines. Sparse matrices consumeren aanzienlijk geheugen en vereisen vaak gespecialiseerde hulpmiddelen en bibliotheken voor efficiënte opslag en berekening, vooral met grote datasets.
- Verlies van betekenis en context: BOW negeert de woordvolgorde en zinsstructuur, wat resulteert in het verlies van grammaticale relaties en betekenis. Deze beperking maakt het minder geschikt voor taken waar context, nuances en woordvolgorde belangrijk zijn, zoals vertaling of sentimentdetectie in complexe zinnen.
De volgende strategieën kunnen worden gebruikt om de omvang van de woordenschat in de Bag of Words te verminderen:
- Het negeren van hoofdletters.
- Het verwijderen van leestekens.
- Het verwijderen van stopwoorden, dat wil zeggen veelvoorkomende woorden zoals de en een.
- Ervoor zorgen dat alle woorden correct gespeld zijn.
- Het gebruik van ontwortelings technieken om woorden tot hun wortelvorm te reduceren.
Volgende Stappen: Verder dan Bag of Words
Eén beperking van het Bag of Words-model is dat het alle woorden gelijk behandelt. Helaas kan dit leiden tot problemen waarbij sommige woorden meer belangrijkheid krijgen puur omdat ze vaak voorkomen.
TF-IDF (Term Frequency-Inverse Document Frequency) is een oplossing voor dit probleem, omdat het het gewicht van woorden aanpast op basis van hoe vaak ze voorkomen in alle documenten.
TF-IDF: Een Uitbreiding op Bag of Words
Term Frequency (TF) vertegenwoordigt de frequentie van een term in een document. Inverse Document Frequency (IDF) vermindert het effect van veelvoorkomende woorden over meerdere documenten. De TF-IDF-score wordt berekend door beide metingen te vermenigvuldigen.
Overweeg een document met 200 woorden, waar het woord liefde 5 keer voorkomt. De TF voor liefde is dan (5 / 200) = 0,025. Aangezien we een miljoen documenten hebben en het woord liefde in duizend van deze voorkomt, wordt de inverse document frequentie (dus, IDF) berekend als log(1000000 / 1000,001) = 3. Het TF-IDF gewicht is het product van deze grootheden: 0,025 * 3 = 0,075.
In Scikit-learn is het relatief eenvoudig om dit te berekenen met behulp van de TfidfVectorizer klasse.
from sklearn.feature_extraction.text import TfidfVectorizer # Sample corpus corpus = [ "Python is amazing and fun.", "Python is not just fun but also powerful.", "Learning Python is fun!", ] # Create the Tf-idf vectorizer tfidf_vectorizer = TfidfVectorizer() # Fit and transform the corpus X_tfidf = tfidf_vectorizer.fit_transform(corpus) # Show the Vocabulary print("Vocabulary:", tfidf_vectorizer.get_feature_names_out()) # Show the TF-IDF Matrix 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]]
De TF-IDF-matrix die hierboven is geïmplementeerd, geeft je een gewogen maat in plaats van ruwe frequenties.
Hoewel het Bag of Words-model beperkingen heeft, vooral voor grotere en complexere datasets, blijft het toch een essentieel bouwsteen in veel NLP-toepassingen. Het begrijpen ervan zal je helpen bij het verkennen van meer geavanceerde modellen zoals woordembedding en Transformers.
Van hieruit kun je experimenteren met BoW in je projecten, inclusief spamdetectie, sentimentanalyse, documentclustering en meer.
Als je verder wilt verbeteren beyond Bag of Words, kun je methoden zoals Word2Vec en GloVe verkennen, of deep learning-modellen zoals BERT.
Eindgedachten
De techniek van de ‘Bag of Words’ is een fundamentele techniek die wordt gebruikt in de Natuurlijke Taalverwerking. Het biedt een eenvoudige yet effectieve manier om ongestructureerde tekst om te zetten in numerieke kenmerken die door machine learning-algoritmen kunnen worden gebruikt. In deze tutorial hebben we besproken:
- Wat is het ‘Bag of Words’ (BoW) model?
- De voordelen van het Bag of Word-model bij het bouwen van machine learning-modellen.
- Hoe het Bag of Words-model in Python te implementeren.
- Voordelen en beperkingen van de Bag of Words.
- De theorie en motivatie achter het Bag of Words-model.
- De introductie van TF-IDF als een verbetering op de traditionele Bag of Words-aanpak.
Kijk eens naar onze Natuurlijke Taalverwerking in Python skill track, om diep in te duiken in natuurlijke taalverwerking.
Source:
https://www.datacamp.com/tutorial/python-bag-of-words-model