En introduktion til Bag of Words og hvordan man koder den i Python til NLP

Bag of Words (BOW) er en metode til at udtrække funktioner fra tekstdokumenter. Disse funktioner kan bruges til træning af maskinlæringsalgoritmer. Det skaber et ordforråd over alle de unikke ord, der forekommer i alle dokumenterne i træningssættet.

Enkelt set er det en samling af ord, der repræsenterer en sætning med antal ord og for det meste ignorerer den rækkefølge, de vises i.

BOW er en tilgang, der er meget brugt med:

  1. Naturlig sprogbehandling
  2. Hentning af oplysninger fra dokumenter
  3. Dokumentklassifikationer

På et højt niveau involverer det følgende trin.

Genererede vektorer kan input til din maskinlæringsalgoritme.

Lad os starte med et eksempel at forstå ved at tage nogle sætninger og generere vektorer til dem.

Overvej nedenstående to sætninger.

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

Disse to sætninger kan også repræsenteres med en ordsamling.

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

Desuden skal du for hver sætning fjerne flere forekomster af ordet og bruge ordtællingen til at repræsentere dette.

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}

Forudsat at disse sætninger er en del af et dokument, er nedenstående den kombinerede ordfrekvens for hele vores dokument. Begge sætninger tages i betragtning.

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

Ovenstående ordforråd fra alle ordene i et dokument med deres respektive antal ord vil blive brugt til at oprette vektorerne til hver af sætningerne.

Længden af ​​vektoren vil altid være lig med ordforrådets størrelse. I dette tilfælde er vektorlængden 11.

For at repræsentere vores originale sætninger i en vektor initialiseres hver vektor med alle nuller - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Dette efterfølges af iteration og sammenligning med hvert ord i vores ordforråd og stigning af vektorværdien, hvis sætningen har det ord.

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]

For eksempel vises i sætning 1 ordet likesi anden position og vises to gange. Så det andet element i vores vektor for sætning 1 vil være 2: [1, 2, 1, 1, 2, 1, 1, 0, 0, 0]

Vektoren er altid proportional med størrelsen på vores ordforråd.

Et stort dokument, hvor det genererede ordforråd er stort, kan resultere i en vektor med masser af 0-værdier. Dette kaldes en sparsom vektor .Sparse vektorer kræver mere hukommelse og beregningsressourcer, når de modelleres. Det store antal positioner eller dimensioner kan gøre modelleringsprocessen meget udfordrende for traditionelle algoritmer.

Kodning af vores BOW-algoritme

Input til vores kode vil være flere sætninger, og output vil være vektorer.

Input arrayet er dette:

["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"]

Trin 1: Tokeniser en sætning

Vi starter med at fjerne stopord fra sætningerne.

Stopord er ord, der ikke indeholder tilstrækkelig betydning til at blive brugt uden vores algoritme. Vi ønsker ikke, at disse ord optager plads i vores database eller tager værdifuld behandlingstid. Til dette kan vi nemt fjerne dem ved at gemme en liste med ord, som du anser for at være stopord.

Tokenisering er handlingen ved at bryde en række strenge op i stykker som ord, nøgleord, sætninger, symboler og andre elementer kaldet tokens . Tokens kan være individuelle ord, sætninger eller endda hele sætninger. I løbet af tokenisering kasseres nogle tegn som tegnsætningstegn.

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

For more robust implementation of stopwords, you can use python nltk library. It has a set of predefined words per language. Here is an example:

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

Step 2: Apply tokenization to all sentences

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

The method iterates all the sentences and adds the extracted word into an array.

The output of this method will be:

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

Step 3: Build vocabulary and generate vectors

Use the methods defined in steps 1 and 2 to create the document vocabulary and extract the words from the sentences.

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)))

Here is the defined input and execution of our code:

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)

The output vectors for each of the sentences are:

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.

Tak, fordi du læste artiklen. Den viste kode er tilgængelig på min GitHub.

Du kan følge mig på Medium, Twitter og LinkedIn. For spørgsmål, kan du kontakte mig på e-mail (praveend806 [at] gmail [dot] com).

Ressourcer til at læse mere om pose med ord

  1. Wikipedia-BOW
  2. Forståelse af Bag-of-Words Model: A Statistical Framework
  3. Semantik-Bevarende taske-med-ord-modeller og applikationer