Uvod u Bag of Words i kako ga kodirati u Pythonu za NLP

Torba riječi (BOW) metoda je za izdvajanje značajki iz tekstualnih dokumenata. Te se značajke mogu koristiti za vježbanje algoritama strojnog učenja. Stvara rječnik svih jedinstvenih riječi koje se pojavljuju u svim dokumentima u setu obuke.

Jednostavno rečeno, to je zbirka riječi koja predstavlja rečenicu s brojem riječi i uglavnom zanemarujući redoslijed kojim se pojavljuju.

BOW je pristup koji se široko koristi sa:

  1. Obrada prirodnog jezika
  2. Dohvaćanje podataka iz dokumenata
  3. Klasifikacije dokumenata

Na visokoj razini uključuje sljedeće korake.

Generirani vektori mogu se unijeti u vaš algoritam strojnog učenja.

Počnimo s primjerom koji ćemo razumjeti uzimajući neke rečenice i generirajući vektore za njih.

Razmotrite dvije donje rečenice.

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

Ove dvije rečenice mogu se predstaviti i zbirkom riječi.

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

Nadalje, za svaku rečenicu uklonite više pojavljivanja riječi i upotrijebite broj riječi da to predstavite.

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}

Pod pretpostavkom da su ove rečenice dio dokumenta, u nastavku je kombinirana učestalost riječi za cijeli naš dokument. U obzir se uzimaju obje rečenice.

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

Gornji rječnik iz svih riječi u dokumentu, s njihovim brojem riječi, koristit će se za stvaranje vektora za svaku od rečenica.

Duljina vektora uvijek će biti jednaka veličini rječnika. U ovom slučaju duljina vektora je 11.

Da bi svoje izvorne rečenice predstavili u vektoru, svaki se vektor inicijalizira sa svim nulama - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Nakon toga slijedi ponavljanje i usporedba sa svakom riječju u našem rječniku te povećavanje vrijednosti vektora ako rečenica ima tu riječ.

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]

Na primjer, u rečenici 1. riječ se likespojavljuje na drugom mjestu i pojavljuje se dva puta. Dakle, drugi element našeg vektora za rečenicu 1 bit će 2: [1, 2, 1, 1, 2, 1, 1, 0, 0, 0]

Vektor je uvijek proporcionalan veličini našeg rječnika.

Veliki dokument u kojem je generirani rječnik ogroman može rezultirati vektorom s puno 0 vrijednosti. To se naziva rijetkim vektorom .Rijetki vektori zahtijevaju više memorije i računskih resursa prilikom modeliranja. Golem broj položaja ili dimenzija može postupak modeliranja učiniti vrlo zahtjevnim za tradicionalne algoritme.

Kodiranje našeg algoritma BOW

Ulaz u naš kôd bit će više rečenica, a izlaz vektori.

Ulazni niz je sljedeći:

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

Korak 1: Označite rečenicu

Započet ćemo uklanjanjem riječi za zaustavljanje iz rečenica.

Lozinke su riječi koje nemaju dovoljno značenja da bi se mogle koristiti bez našeg algoritma. Ne bismo željeli da ove riječi zauzimaju prostor u našoj bazi podataka ili da oduzimaju dragocjeno vrijeme obrade. Zbog toga ih možemo lako ukloniti spremanjem popisa riječi za koje smatrate da su zaustavne riječi.

Tokenizacija je čin razbijanja niza nizova na dijelove kao što su riječi, ključne riječi, fraze, simboli i drugi elementi koji se nazivaju žetoni . Žetoni mogu biti pojedinačne riječi, fraze ili čak cijele rečenice. U procesu tokenizacije neki se znakovi poput interpunkcijskih znakova odbacuju.

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

Za robusniju implementaciju zaustavnih riječi možete koristiti python nltk knjižnicu. Ima skup unaprijed definiranih riječi po jeziku. Evo primjera:

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

Korak 2: Primijenite tokenizaciju na sve rečenice

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

Metoda ponavlja sve rečenice i dodaje izdvojenu riječ u niz.

Rezultat ove metode bit će:

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

Korak 3: Izgradite rječnik i generirajte vektore

Upotrijebite metode definirane u koracima 1 i 2 za stvaranje rječnika dokumenta i izdvajanje riječi iz rečenica.

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

Evo definiranog unosa i izvršavanja našeg koda:

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)

Izlazni vektori za svaku od rečenica su:

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