Eine Einführung in Bag of Words und wie man es in Python für NLP codiert

Bag of Words (BOW) ist eine Methode zum Extrahieren von Features aus Textdokumenten. Diese Funktionen können zum Trainieren von Algorithmen für maschinelles Lernen verwendet werden. Es wird ein Vokabular aller eindeutigen Wörter erstellt, die in allen Dokumenten des Trainingssatzes vorkommen.

In einfachen Worten, es ist eine Sammlung von Wörtern, die einen Satz mit Wortanzahl darstellen und die Reihenfolge, in der sie erscheinen, größtenteils außer Acht lassen.

BOW ist ein weit verbreiteter Ansatz mit:

  1. Verarbeitung natürlicher Sprache
  2. Informationsabruf aus Dokumenten
  3. Dokumentklassifizierungen

Auf hoher Ebene umfasst es die folgenden Schritte.

Generierte Vektoren können in Ihren Algorithmus für maschinelles Lernen eingegeben werden.

Beginnen wir mit einem Beispiel zum Verstehen, indem wir einige Sätze nehmen und Vektoren für diese generieren.

Betrachten Sie die folgenden zwei Sätze.

1. "John likes to watch movies. Mary likes movies too."
2. "John also likes to watch football games."

Diese beiden Sätze können auch mit einer Sammlung von Wörtern dargestellt werden.

1. ['John', 'likes', 'to', 'watch', 'movies.', 'Mary', 'likes', 'movies', 'too.']
2. ['John', 'also', 'likes', 'to', 'watch', 'football', 'games']

Entfernen Sie außerdem für jeden Satz mehrere Vorkommen des Wortes und verwenden Sie die Wortanzahl, um dies darzustellen.

1. {"John":1,"likes":2,"to":1,"watch":1,"movies":2,"Mary":1,"too":1}
2. {"John":1,"also":1,"likes":1,"to":1,"watch":1,"football":1, "games":1}

Angenommen, diese Sätze sind Teil eines Dokuments. Nachfolgend finden Sie die kombinierte Worthäufigkeit für unser gesamtes Dokument. Beide Sätze werden berücksichtigt.

 {"John":2,"likes":3,"to":2,"watch":2,"movies":2,"Mary":1,"too":1, "also":1,"football":1,"games":1}

Das obige Vokabular aus allen Wörtern in einem Dokument mit ihrer jeweiligen Wortzahl wird verwendet, um die Vektoren für jeden der Sätze zu erstellen.

Die Länge des Vektors entspricht immer der Vokabulargröße. In diesem Fall beträgt die Vektorlänge 11.

Um unsere ursprünglichen Sätze in einem Vektor darzustellen, wird jeder Vektor mit allen Nullen initialisiert - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Darauf folgt die Iteration und der Vergleich mit jedem Wort in unserem Wortschatz und das Erhöhen des Vektorwerts, wenn der Satz dieses Wort enthält.

John likes to watch movies. Mary likes movies too.[1, 2, 1, 1, 2, 1, 1, 0, 0, 0]
John also likes to watch football games.[1, 1, 1, 1, 0, 0, 0, 1, 1, 1]

In Satz 1 steht das Wort beispielsweise likesan zweiter Stelle und zweimal. Das zweite Element unseres Vektors für Satz 1 ist also 2: [1, 2, 1, 1, 2, 1, 1, 0, 0, 0]

Der Vektor ist immer proportional zur Größe unseres Wortschatzes.

Ein großes Dokument, in dem das generierte Vokabular sehr groß ist, kann zu einem Vektor mit vielen 0-Werten führen. Dies wird als spärlicher Vektor bezeichnet .Bei spärlichen Vektoren sind beim Modellieren mehr Speicher und Rechenressourcen erforderlich. Die große Anzahl von Positionen oder Dimensionen kann den Modellierungsprozess für herkömmliche Algorithmen sehr schwierig machen.

Codierung unseres BOW-Algorithmus

Die Eingabe in unseren Code besteht aus mehreren Sätzen und die Ausgabe sind die Vektoren.

Das Eingabearray lautet wie folgt:

["Joe waited for the train", "The train was late", "Mary and Samantha took the bus",
"I looked for Mary and Samantha at the bus station",
"Mary and Samantha arrived at the bus station early but waited until noon for the bus"]

Schritt 1: Tokenisieren Sie einen Satz

Wir beginnen damit, Stoppwörter aus den Sätzen zu entfernen.

Stoppwörter sind Wörter, die nicht genügend Bedeutung haben, um ohne unseren Algorithmus verwendet zu werden. Wir möchten nicht, dass diese Wörter Speicherplatz in unserer Datenbank beanspruchen oder wertvolle Verarbeitungszeit beanspruchen. Zu diesem Zweck können wir sie leicht entfernen, indem wir eine Liste von Wörtern speichern, die Sie als Stoppwörter betrachten.

Tokenisierung ist der Vorgang des Aufbrechens einer Folge von Zeichenfolgen in Teile wie Wörter, Schlüsselwörter, Phrasen, Symbole und andere Elemente, die als Token bezeichnet werden . Token können einzelne Wörter, Phrasen oder sogar ganze Sätze sein. Bei der Tokenisierung werden einige Zeichen wie Satzzeichen verworfen.

def word_extraction(sentence): ignore = ['a', "the", "is"] words = re.sub("[^\w]", " ", sentence).split() cleaned_text = [w.lower() for w in words if w not in ignore] return cleaned_text

Für eine robustere Implementierung von Stoppwörtern können Sie die Python nltk- Bibliothek verwenden. Es enthält eine Reihe vordefinierter Wörter pro Sprache. Hier ist ein Beispiel:

import nltkfrom nltk.corpus import stopwords set(stopwords.words('english'))

Schritt 2: Wenden Sie die Tokenisierung auf alle Sätze an

def tokenize(sentences): words = [] for sentence in sentences: w = word_extraction(sentence) words.extend(w) words = sorted(list(set(words))) return words

Die Methode iteriert alle Sätze und fügt das extrahierte Wort einem Array hinzu.

Die Ausgabe dieser Methode lautet:

['and', 'arrived', 'at', 'bus', 'but', 'early', 'for', 'i', 'joe', 'late', 'looked', 'mary', 'noon', 'samantha', 'station', 'the', 'took', 'train', 'until', 'waited', 'was']

Schritt 3: Bauen Sie Vokabeln auf und generieren Sie Vektoren

Verwenden Sie die in den Schritten 1 und 2 definierten Methoden, um das Dokumentvokabular zu erstellen und die Wörter aus den Sätzen zu extrahieren.

def generate_bow(allsentences): vocab = tokenize(allsentences) print("Word List for Document \n{0} \n".format(vocab));
for sentence in allsentences: words = word_extraction(sentence) bag_vector = numpy.zeros(len(vocab)) for w in words: for i,word in enumerate(vocab): if word == w: bag_vector[i] += 1 print("{0}\n{1}\n".format(sentence,numpy.array(bag_vector)))

Hier ist die definierte Eingabe und Ausführung unseres Codes:

allsentences = ["Joe waited for the train train", "The train was late", "Mary and Samantha took the bus",
"I looked for Mary and Samantha at the bus station",
"Mary and Samantha arrived at the bus station early but waited until noon for the bus"]
generate_bow(allsentences)

Die Ausgabevektoren für jeden der Sätze sind:

Output:
Joe waited for the train train[0. 0. 0. 0. 0. 0. 1. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 2. 0. 1. 0.]
The train was late[0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 1. 0. 1. 0. 0. 1.]
Mary and Samantha took the bus[1. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 1. 0. 1. 0. 0. 1. 0. 0. 0. 0.]
I looked for Mary and Samantha at the bus station[1. 0. 1. 1. 0. 0. 1. 1. 0. 0. 1. 1. 0. 1. 1. 0. 0. 0. 0. 0. 0.]
Mary and Samantha arrived at the bus station early but waited until noon for the bus[1. 1. 1. 2. 1. 1. 1. 0. 0. 0. 0. 1. 1. 1. 1. 0. 0. 0. 1. 1. 0.]

As you can see, each sentence was compared with our word list generated in Step 1. Based on the comparison, the vector element value may be incremented. These vectors can be used in ML algorithms for document classification and predictions.

We wrote our code and generated vectors, but now let’s understand bag of words a bit more.

Insights into bag of words

The BOW model only considers if a known word occurs in a document or not. It does not care about meaning, context, and order in which they appear.

This gives the insight that similar documents will have word counts similar to each other. In other words, the more similar the words in two documents, the more similar the documents can be.

Limitations of BOW

  1. Semantic meaning: the basic BOW approach does not consider the meaning of the word in the document. It completely ignores the context in which it’s used. The same word can be used in multiple places based on the context or nearby words.
  2. Vector size: For a large document, the vector size can be huge resulting in a lot of computation and time. You may need to ignore words based on relevance to your use case.

This was a small introduction to the BOW method. The code showed how it works at a low level. There is much more to understand about BOW. For example, instead of splitting our sentence in a single word (1-gram), you can split in the pair of two words (bi-gram or 2-gram). At times, bi-gram representation seems to be much better than using 1-gram. These can often be represented using N-gram notation. I have listed some research papers in the resources section for more in-depth knowledge.

You do not have to code BOW whenever you need it. It is already part of many available frameworks like CountVectorizer in sci-kit learn.

Our previous code can be replaced with:

from sklearn.feature_extraction.text import CountVectorizervectorizer = CountVectorizer()X = vectorizer.fit_transform(allsentences)print(X.toarray())

It’s always good to understand how the libraries in frameworks work, and understand the methods behind them. The better you understand the concepts, the better use you can make of frameworks.

Thanks for reading the article. The code shown is available on my GitHub.

You can follow me on Medium, Twitter, and LinkedIn, For any questions, you can reach out to me on email (praveend806 [at] gmail [dot] com).

Resources to read more on bag of words

  1. Wikipedia-BOW
  2. Understanding Bag-of-Words Model: A Statistical Framework
  3. Semantics-Preserving Bag-of-Words Models and Applications