A Gentle Introduction to the Bag-of-Words Model

The bag-of-words model is a way of representing text data when modeling text with machine learning algorithms.

The bag-of-words model is simple to understand and implement and has seen great success in problems such as language modeling and document classification.

In this tutorial, you will discover the bag-of-words model for feature extraction in natural language processing.

After completing this tutorial, you will know:

  • What the bag-of-words model is and why it is needed to represent text.
  • How to develop a bag-of-words model for a collection of documents.
  • How to use different techniques to prepare a vocabulary and score words.

Let’s get started.

A Gentle Introduction to the Bag-of-Words Model

A Gentle Introduction to the Bag-of-Words Model
Photo by Do8y, some rights reserved.

Tutorial Overview

This tutorial is divided into 6 parts; they are:

  1. The Problem with Text
  2. What is a Bag-of-Words?
  3. Example of the Bag-of-Words Model
  4. Managing Vocabulary
  5. Scoring Words
  6. Limitations of Bag-of-Words

Need help with Deep Learning for Text Data?

Take my free 7-day email crash course now (with code).

Click to sign-up and also get a free PDF Ebook version of the course.

Start Your FREE Crash-Course Now

The Problem with Text

A problem with modeling text is that it is messy, and techniques like machine learning algorithms prefer well defined fixed-length inputs and outputs.

Machine learning algorithms cannot work with raw text directly; the text must be converted into numbers. Specifically, vectors of numbers.

In language processing, the vectors x are derived from textual data, in order to reflect various linguistic properties of the text.

— Page 65, Neural Network Methods in Natural Language Processing, 2017.

This is called feature extraction or feature encoding.

A popular and simple method of feature extraction with text data is called the bag-of-words model of text.

What is a Bag-of-Words?

A bag-of-words model, or BoW for short, is a way of extracting features from text for use in modeling, such as with machine learning algorithms.

The approach is very simple and flexible, and can be used in a myriad of ways for extracting features from documents.

A bag-of-words is a representation of text that describes the occurrence of words within a document. It involves two things:

  1. A vocabulary of known words.
  2. A measure of the presence of known words.

It is called a “bag” of words, because any information about the order or structure of words in the document is discarded. The model is only concerned with whether known words occur in the document, not where in the document.

A very common feature extraction procedures for sentences and documents is the bag-of-words approach (BOW). In this approach, we look at the histogram of the words within the text, i.e. considering each word count as a feature.

— Page 69, Neural Network Methods in Natural Language Processing, 2017.

The intuition is that documents are similar if they have similar content. Further, that from the content alone we can learn something about the meaning of the document.

The bag-of-words can be as simple or complex as you like. The complexity comes both in deciding how to design the vocabulary of known words (or tokens) and how to score the presence of known words.

We will take a closer look at both of these concerns.

Example of the Bag-of-Words Model

Let’s make the bag-of-words model concrete with a worked example.

Step 1: Collect Data

Below is a snippet of the first few lines of text from the book “A Tale of Two Cities” by Charles Dickens, taken from Project Gutenberg.

It was the best of times,
it was the worst of times,
it was the age of wisdom,
it was the age of foolishness,

For this small example, let’s treat each line as a separate “document” and the 4 lines as our entire corpus of documents.

Step 2: Design the Vocabulary

Now we can make a list of all of the words in our model vocabulary.

The unique words here (ignoring case and punctuation) are:

  • “it”
  • “was”
  • “the”
  • “best”
  • “of”
  • “times”
  • “worst”
  • “age”
  • “wisdom”
  • “foolishness”

That is a vocabulary of 10 words from a corpus containing 24 words.

Step 3: Create Document Vectors

The next step is to score the words in each document.

The objective is to turn each document of free text into a vector that we can use as input or output for a machine learning model.

Because we know the vocabulary has 10 words, we can use a fixed-length document representation of 10, with one position in the vector to score each word.

The simplest scoring method is to mark the presence of words as a boolean value, 0 for absent, 1 for present.

Using the arbitrary ordering of words listed above in our vocabulary, we can step through the first document (“It was the best of times“) and convert it into a binary vector.

The scoring of the document would look as follows:

  • “it” = 1
  • “was” = 1
  • “the” = 1
  • “best” = 1
  • “of” = 1
  • “times” = 1
  • “worst” = 0
  • “age” = 0
  • “wisdom” = 0
  • “foolishness” = 0

As a binary vector, this would look as follows:

The other three documents would look as follows:

All ordering of the words is nominally discarded and we have a consistent way of extracting features from any document in our corpus, ready for use in modeling.

New documents that overlap with the vocabulary of known words, but may contain words outside of the vocabulary, can still be encoded, where only the occurrence of known words are scored and unknown words are ignored.

You can see how this might naturally scale to large vocabularies and larger documents.

Managing Vocabulary

As the vocabulary size increases, so does the vector representation of documents.

In the previous example, the length of the document vector is equal to the number of known words.

You can imagine that for a very large corpus, such as thousands of books, that the length of the vector might be thousands or millions of positions. Further, each document may contain very few of the known words in the vocabulary.

This results in a vector with lots of zero scores, called a sparse vector or sparse representation.

Sparse vectors require more memory and computational resources when modeling and the vast number of positions or dimensions can make the modeling process very challenging for traditional algorithms.

As such, there is pressure to decrease the size of the vocabulary when using a bag-of-words model.

There are simple text cleaning techniques that can be used as a first step, such as:

  • Ignoring case
  • Ignoring punctuation
  • Ignoring frequent words that don’t contain much information, called stop words, like “a,” “of,” etc.
  • Fixing misspelled words.
  • Reducing words to their stem (e.g. “play” from “playing”) using stemming algorithms.

A more sophisticated approach is to create a vocabulary of grouped words. This both changes the scope of the vocabulary and allows the bag-of-words to capture a little bit more meaning from the document.

In this approach, each word or token is called a “gram”. Creating a vocabulary of two-word pairs is, in turn, called a bigram model. Again, only the bigrams that appear in the corpus are modeled, not all possible bigrams.

An N-gram is an N-token sequence of words: a 2-gram (more commonly called a bigram) is a two-word sequence of words like “please turn”, “turn your”, or “your homework”, and a 3-gram (more commonly called a trigram) is a three-word sequence of words like “please turn your”, or “turn your homework”.

— Page 85, Speech and Language Processing, 2009.

For example, the bigrams in the first line of text in the previous section: “It was the best of times” are as follows:

  • “it was”
  • “was the”
  • “the best”
  • “best of”
  • “of times”

A vocabulary then tracks triplets of words is called a trigram model and the general approach is called the n-gram model, where n refers to the number of grouped words.

Often a simple bigram approach is better than a 1-gram bag-of-words model for tasks like documentation classification.

a bag-of-bigrams representation is much more powerful than bag-of-words, and in many cases proves very hard to beat.

— Page 75, Neural Network Methods in Natural Language Processing, 2017.

Scoring Words

Once a vocabulary has been chosen, the occurrence of words in example documents needs to be scored.

In the worked example, we have already seen one very simple approach to scoring: a binary scoring of the presence or absence of words.

Some additional simple scoring methods include:

  • Counts. Count the number of times each word appears in a document.
  • Frequencies. Calculate the frequency that each word appears in a document out of all the words in the document.

Word Hashing

You may remember from computer science that a hash function is a bit of math that maps data to a fixed size set of numbers.

For example, we use them in hash tables when programming where perhaps names are converted to numbers for fast lookup.

We can use a hash representation of known words in our vocabulary. This addresses the problem of having a very large vocabulary for a large text corpus because we can choose the size of the hash space, which is in turn the size of the vector representation of the document.

Words are hashed deterministically to the same integer index in the target hash space. A binary score or count can then be used to score the word.

This is called the “hash trick” or “feature hashing“.

The challenge is to choose a hash space to accommodate the chosen vocabulary size to minimize the probability of collisions and trade-off sparsity.

TF-IDF

A problem with scoring word frequency is that highly frequent words start to dominate in the document (e.g. larger score), but may not contain as much “informational content” to the model as rarer but perhaps domain specific words.

One approach is to rescale the frequency of words by how often they appear in all documents, so that the scores for frequent words like “the” that are also frequent across all documents are penalized.

This approach to scoring is called Term Frequency – Inverse Document Frequency, or TF-IDF for short, where:

  • Term Frequency: is a scoring of the frequency of the word in the current document.
  • Inverse Document Frequency: is a scoring of how rare the word is across documents.

The scores are a weighting where not all words are equally as important or interesting.

The scores have the effect of highlighting words that are distinct (contain useful information) in a given document.

Thus the idf of a rare term is high, whereas the idf of a frequent term is likely to be low.

— Page 118, An Introduction to Information Retrieval, 2008.

Limitations of Bag-of-Words

The bag-of-words model is very simple to understand and implement and offers a lot of flexibility for customization on your specific text data.

It has been used with great success on prediction problems like language modeling and documentation classification.

Nevertheless, it suffers from some shortcomings, such as:

  • Vocabulary: The vocabulary requires careful design, most specifically in order to manage the size, which impacts the sparsity of the document representations.
  • Sparsity: Sparse representations are harder to model both for computational reasons (space and time complexity) and also for information reasons, where the challenge is for the models to harness so little information in such a large representational space.
  • Meaning: Discarding word order ignores the context, and in turn meaning of words in the document (semantics). Context and meaning can offer a lot to the model, that if modeled could tell the difference between the same words differently arranged (“this is interesting” vs “is this interesting”), synonyms (“old bike” vs “used bike”), and much more.

Further Reading

This section provides more resources on the topic if you are looking go deeper.

Articles

Books

Summary

In this tutorial, you discovered the bag-of-words model for feature extraction with text data.

Specifically, you learned:

  • What the bag-of-words model is and why we need it.
  • How to work through the application of a bag-of-words model to a collection of documents.
  • What techniques can be used for preparing a vocabulary and scoring words.

Do you have any questions?
Ask your questions in the comments below and I will do my best to answer.


Develop Deep Learning models for Text Data Today!

Deep Learning for Natural Language Processing

Develop Your Own Text models in Minutes

…with just a few lines of python code

Discover how in my new Ebook:
Deep Learning for Natural Language Processing

It provides self-study tutorials on topics like:
Bag-of-Words, Word Embedding, Language Models, Caption Generation, Text Translation and much more…

Finally Bring Deep Learning to your Natural Language Processing Projects

Skip the Academics. Just Results.

Click to learn more.


39 Responses to A Gentle Introduction to the Bag-of-Words Model

  1. Samuel October 13, 2017 at 6:00 am #

    Great article, thanks for keeping it concise and still easy to understand and read.

  2. meow October 13, 2017 at 4:58 pm #

    great read and good references.

  3. Osama Hamed October 18, 2017 at 1:33 am #

    It is really a gentle intro.

  4. Fatma January 9, 2018 at 9:25 pm #

    Very helpful and clear step by step explanation.

    Thanks.
    Fatma

  5. Anna January 26, 2018 at 5:55 am #

    Hi Jason,

    Great article! So, since using Bag-of-Words does not take into account the relation between words or word order. Does transferring the Bag-of-Words model into CNN could tackle the problem and increase the prediction accuracy? I’ve been searching for the article of implementing BOW + CNN for text classification but no luck so far.

    Thank you

    • Jason Brownlee January 27, 2018 at 5:47 am #

      No. But you could use a word embedding and an LSTM that would learn the relationship between words.

  6. zenith February 14, 2018 at 4:24 am #

    If I understood it correctly, the purpose of word hashing is to easily map the value to the word and get to easily update the count. My question is, would it be easier if I just use a dictionary instead of implementing word hashing?

  7. Georgy March 23, 2018 at 4:14 am #

    Thank you for article
    i dont actually understand what bag of words is after reading
    1) The binary vector is the ready BOW model output?
    [1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
    2) How would it look like if we have more than one occurrence of a word?
    [1, 1, 2, 1, 1, 1, 0, 0, 0, 0] (not a strict example but suppose “the” was twice in the doc)
    3) I dont understand why we cant put bag of words into rnn models? Into lstm for example

    • Jason Brownlee March 23, 2018 at 6:12 am #

      The representation of a document as a vector of word frequencies is the BoW model.

      You can choose how to count, either exists/not-exists, or a count, or something else.

      We can plug words into RNNs, often we use a word embedding on the front end to get a more distributed representation of the words:
      https://machinelearningmastery.com/what-are-word-embeddings/

      Does that help Georgy?

  8. Chen-Feng Tsen May 22, 2018 at 5:38 am #

    Hello! Thank you for your illustration. We are doing a project of music genre classification based on the song lyrics. However, due to the license issue we only obtained the lyrics in a bag-of-words format and couldn’t access the full lyrics. We are trying to use TFIDF, in combination of bag-of-words model. However, in our case we couldn’t get document vectors since we don’t have information of complete sentences. Do we need to get the full lyric texts to do the training? Or is it sufficient to implement the model with the data we have right now? Thank you very much!

    • Jason Brownlee May 22, 2018 at 6:32 am #

      See how far you can get with BoW. To use the embedding/LSTM you will need the original docs.

  9. Lakshmikanth K A June 23, 2018 at 5:19 am #

    Say I have 10 documents. After removing stop words and stemming etc. I have 50 word vocabulary. My each document would be a vector of 50 tf-idf values which I will model using the dependent variable. That means my modeling data has 10rows*50 features + 1 dependent column..And each cell holds the tf-idf of that vocabulary word. Is this right approach?

    Also, tf-if is a value is a function the term and document and all the documents., Since tf comes from what is the term and what is it’s frequency in a given document…And idf comes from what is that term’s frequency in the overall set of all documents.
    Is this understanding right?

    Or is tf-idf …After being computed….is summarized at a term level or a document level??

    • Jason Brownlee June 23, 2018 at 6:21 am #

      Yes, it is terms described statistically within and across documents in the corpus.

  10. Nil July 5, 2018 at 4:09 pm #

    Hi, DR. Jason,

    I have two questions, I am seeking for help:
    1. I saw something called Term Document Matrix (TDM) in R is it the same thing as Bag-of-Words in Python?
    2. I read from one of your posts about Bag-of-Words result in a sparse vector I would like to know if after having the sparse vector is necessary to convert them in a dense vector before using whit machine learning algorithms.

    Best Regards

    • Jason Brownlee July 6, 2018 at 6:39 am #

      I don’t know about TDM sorry.

      No need to convert to dense.

      • Nil July 7, 2018 at 2:16 am #

        Understood. Thanks.

  11. Enrico Marzon July 7, 2018 at 12:07 pm #

    Hi. I just want to ask if I can use the Bag Of Words Model in filtering word. For example, I got the tweets from Twitter, then I need to filter those tweets which I will consider as relevant data. And those filtered data will be used for classification.

    I need your help about this. Thank you in advance.

    • Jason Brownlee July 8, 2018 at 6:15 am #

      Sorry, I don’t have an example of text filtering, I cannot give you good advice.

  12. Mohammad July 14, 2018 at 2:27 am #

    Hey Dr. Jason,

    thank you so much.
    It is really a gentle and great introduction.

  13. Valentina Rodrigues July 26, 2018 at 8:27 pm #

    You have mentioned this:
    This results in a vector with lots of zero scores, called a sparse vector or sparse representation.

    But in Google’s ML Crash Course they have mentioned this:

    * A dense representation of this sentence must set an integer for all one million cells, placing a 0 in most of them, and a low integer into a few of them.

    * A sparse representation of this sentence stores only those cells symbolizing a word actually in the sentence. So, if the sentence contained only 20 unique words, then the sparse representation for the sentence would store an integer in only 20 cells.

    Link: https://developers.google.com/machine-learning/glossary/#sparse_features

  14. Adi August 1, 2018 at 2:49 am #

    Hi Jason, excellent article. I’m trying to categorize Tweets based on topics. Ex. tweets with amazon get placed into one cluster, and tweets with netflix get put into another cluster. Say there are 3 topics, A, B, C. My incoming stream of tweets is ABABAACCABA etc. I just need to cluster these into their respective groups. I’m using Spark Streaming, and the StreamingKMeans model to do this.

    How can I vectorize tweets such that those vectors when predicted on by the K-Means model, get placed in the same cluster

    • Jason Brownlee August 1, 2018 at 7:47 am #

      Sorry, I don’t have examples of working with streaming models.

  15. Avinish August 5, 2018 at 9:17 pm #

    Hi Jason,

    How can you model a system where you have a collection of documents mapped to some labels, and some unlabelled examples.

    Document label
    D1 —- c1
    D2 —- c2
    D3 —- c3
    .
    .
    .
    .
    .
    Dk —– c1

    Two questions here:-

    Q1. The lables I might see in the future might be different from what I have at trainig time
    and even the corpus might change to some extent.So I have to apply semi-supervised
    or unsupervised learning to learn online(on the fly) and then do better in later predictions
    for the seen label, classifying into appropriate class(label).

    Q2. If i see a label which I have already seen lets say(c1) and I come across similiar feature
    vector, I just classify it as 1 and if I see label lets say ck, I predict it as 0 if ck was never
    seen before but should have the ability to learn this and later on predict 1 for ck as well.
    Basically classifying into bi-class classification as some ticket having a parent ticket
    (predicting 1) and not having any parent ticket(0).Text documents here are ticket
    descriptions.

    I am struggling to devise an architecture for the problem itself, it would be really helpful if you could guide me regarding this.

    • Jason Brownlee August 6, 2018 at 6:27 am #

      Sorry, I don’t have examples of semi-supervised learning.

  16. Ravi Singh August 7, 2018 at 4:48 pm #

    Hi, I followed the tutorial and Now I have a model which I trained using Bag of Word,
    What I did was converted my text into Sparse Matrix and trained the model. It is giving 95 percent accuracy but now I am unable to predict a simple statement using the model.

    This is my code –

    I have a data frame with 2 classes labels and body.

    # using bag of word model for the same
    cout_vect = CountVectorizer()
    # Convert from object to unicode
    final_count = cout_vect.fit_transform(df[‘body’].values.astype(‘U’))

    #model
    # Using a classifier for the bag of word representation
    from sklearn.model_selection import train_test_split
    from keras.models import Sequential
    from keras.layers import Dense
    from keras.wrappers.scikit_learn import KerasClassifier
    from keras.utils import np_utils
    X_train, X_test, y_train, y_test = train_test_split(final_count, df[‘label’], test_size = .3, random_state=25)

    model = Sequential()
    model.add(Dense(264, input_dim=X_train.shape[1], activation=’relu’))
    model.add(Dense(128, activation=’relu’))
    model.add(Dense(64, activation=’relu’))
    model.add(Dense(32, activation=’relu’))
    model.add(Dense(16, activation=’relu’))
    model.add(Dense(8, activation=’relu’))
    model.add(Dense(3, activation=’softmax’))
    # Compile model
    model.compile(loss=’categorical_crossentropy’, optimizer=’adam’, metrics=[‘accuracy’])
    y_train = np_utils.to_categorical(y_train, num_classes=3)
    y_test = np_utils.to_categorical(y_test, num_classes=3)

    model.fit(X_train, y_train, epochs=50, batch_size=32)
    model.evaluate(x=X_test, y=y_test, batch_size=None, verbose=1, sample_weight=None)

    Now I want to predict this statement using my model. How to do this

    x = “Your account balance has been deducted for 4300”

    model.predict(x, batch_size=None, verbose=0, steps=None)

    • Jason Brownlee August 8, 2018 at 6:15 am #

      Well done.

      To make a prediction you must prepare the input in the same way as you did the training data.

  17. shubham October 26, 2018 at 9:43 pm #

    Hi,
    I followed this article.I want to ask how can we extract some difficult words(terminologies) from l
    different document and store it in vector to make it as the vocabulary for the machine.Will BoW be better solution or should i look for something else.

    • Jason Brownlee October 27, 2018 at 5:59 am #

      Not sure I follow.

      Bag of words and word2vec are two popular representations for text data in machine learning.

  18. Mike November 7, 2018 at 12:33 pm #

    Really fantastic article. Excellent clarity. Thanks Jason!

  19. mustafa December 7, 2018 at 10:09 pm #

    Thanks for this informative article. I wonder
    What is the difference between BOW and TF?
    Are these same things?

    • Jason Brownlee December 8, 2018 at 7:07 am #

      BOW and TF?

      Bag of words and term frequency?

      Same generally, although the vector can be filled with counts, binary, proportions, etc.

Leave a Reply