Вступ до Bag of Words і про те, як його кодувати на Python для NLP

Сумка слів (BOW) - це метод вилучення об’єктів із текстових документів. Ці функції можна використовувати для навчання алгоритмів машинного навчання. Це створює словниковий запас усіх унікальних слів, що містяться у всіх документах навчального набору.

Простіше кажучи, це сукупність слів, що представляють речення з підрахунком слів і переважно не враховуючи порядок їх появи.

BOW - це підхід, який широко використовується з:

  1. Обробка природної мови
  2. Пошук інформації з документів
  3. Класифікації документів

На високому рівні це передбачає наступні кроки.

Сформовані вектори можуть бути введені в ваш алгоритм машинного навчання.

Почнемо з прикладу, щоб зрозуміти це, взявши кілька речень і створивши вектори для них.

Розгляньте два нижченаведені речення.

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

Ці два речення також можна представити збіркою слів.

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

Крім того, для кожного речення видаліть кілька випадків, коли слово входить, і використовуйте кількість слів, щоб представити це.

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}

Якщо припустити, що ці речення є частиною документа, нижче наведена загальна частота слів для всього нашого документа. Враховано обидва речення.

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

Вищевказаний словниковий запас із усіх слів у документі із відповідною кількістю слів буде використаний для створення векторів для кожного з речень.

Довжина вектора завжди буде дорівнює розміру словника. У цьому випадку довжина вектора дорівнює 11.

Для того, щоб представити наші оригінальні речення у векторі, кожен вектор ініціалізується з усіма нулями - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Далі слідує ітерація та порівняння з кожним словом у нашому словниковому запасі та збільшення вектору, якщо речення має це слово.

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]

Наприклад, у реченні 1 слово likesз’являється на другій позиції та з’являється два рази. Отже, другим елементом нашого вектора для речення 1 буде 2: [1, 2, 1, 1, 2, 1, 1, 0, 0, 0]

Вектор завжди пропорційний розміру нашого словникового запасу.

Великий документ, де сформований словниковий запас величезний, може призвести до вектора з великою кількістю значень 0. Це називається розрідженим вектором .Розріджені вектори вимагають більше пам'яті та обчислювальних ресурсів при моделюванні. Величезна кількість позицій або розмірів може зробити процес моделювання дуже складним для традиційних алгоритмів.

Кодування нашого алгоритму BOW

Вхідними даними нашого коду буде декілька речень, а вихідними будуть вектори.

Вхідний масив такий:

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

Крок 1: Лексема речення

Почнемо з того, що вилучимо із речень стоп-слова.

Стоп- слова - це слова, які не мають достатньої значущості для використання без нашого алгоритму. Ми не хотіли б, щоб ці слова займали місце в нашій базі даних або займали цінний час на обробку. Для цього ми можемо їх легко видалити, зберігаючи список слів, які ви вважаєте зупинними словами.

Токенізація - це акт розбиття послідовності рядків на частини, такі як слова, ключові слова, фрази, символи та інші елементи, які називаються лексемами . Лексеми можуть бути окремими словами, фразами або навіть цілими реченнями. У процесі токенізації деякі символи, такі як розділові знаки, відкидаються.

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

Для більш надійної реалізації зупинних слів ви можете використовувати бібліотеку python nltk . Він має набір заздалегідь визначених слів для кожної мови. Ось приклад:

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

Крок 2: Застосуйте токенізацію до всіх речень

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

Метод повторює всі речення та додає витягнуте слово до масиву.

Результатом цього методу буде:

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

Крок 3: Створіть словниковий запас та сформуйте вектори

Використовуйте методи, визначені в кроках 1 і 2, для створення словникового запасу документа та вилучення слів із речень.

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

Ось визначене введення та виконання нашого коду:

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)

Вихідними векторами для кожного з речень є:

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