One of the most widely used methods natural language is n-gram modeling. This article explains what an n-gram model is, how it is computed, and what the probabilities of an n-gram model tell us.

What is an n-gram?#

An n-gram is a contiguous sequence of n items from a given sequence of text. Given a sentence, `s`, we can construct a list of n-grams from `s` by finding pairs of words that occur next to each other. For example, given the sentence “I am Sam” you can construct bigrams (n-grams of length 2) by finding consecutive pairs of words.

``````>>> s = "I am Sam."
>>> tokens = s.split(" ")
>>> bigrams = [(tokens[i],tokens[i+1]) for i in range(0,len(tokens)-1)]
>>> bigrams
[('I', 'am'), ('am', 'Sam.')]
``````

Calculating n-gram Probability#

Given a list of n-grams we can count the number of occurrences of each n-gram; this count determines the frequency with which an n-gram occurs throughout our document.

``````>>> from collections import Counter
>>> count = Counter(bigrams)
>>> count
[(('am', 'Sam.'), 1), (('I', 'am'), 1)]
``````

With this small corpus we only count one occurrence of each n-gram. By dividing these counts by the size of all n-grams in our list we would get a probability of 0.5 of each n-gram occurring.

Let’s look a larger corpus of words and see what the probabilities can tell us. The following sequence of bigrams was computed from data downloaded from HC Corpora. It lists the 20 most frequently encountered bigrams out of 97,810,566 bigrams in the entire corpus.

This data represents the most frequently used pairs of words in the corpus along with the number of times they occur.

``````of	the	421560
in	the	380608
to	the	207571
for	the	190683
on	the	184430
to	be	153285
at	the	128980
and	the	114232
in	a	109527
with	the	99141
is	a	99053
for	a	90209
from	the	82223
with	a	78918
will	be	78049
of	a	78009
I	was	76788
I	have	76621
going	to	75088
is	the	70045
``````

By consulting our frequency table of bigrams, we can tell that the sentence `There was heavy rain last night` is much more likely to be grammatically correct than the sentence `There was large rain last night` by the fact that the bigram `heavy rain` occurs much more frequently than `large rain` in our corpus. Said another way, the probability of the bigram `heavy rain` is larger than the probability of the bigram `large rain`.

Sentences as probability models#

More precisely, we can use n-gram models to derive a probability of the sentence ,`W`, as the joint probability of each individual word in the sentence, `wi`.

``````P(W) = P(w1, w2, ..., wn)
``````

This can be reduced to a sequence of n-grams using the Chain Rule of conditional probability.

``````P(x1, x2, ..., xn) = P(x1)P(x2|x1)...P(xn|x1,...xn-1)
``````

As a concrete example, let’s predict the probability of the sentence `There was heavy rain`.

``````P('There was heavy rain') = P('There', 'was', 'heavy', 'rain')
P('There was heavy rain') = P('There')P('was'|'There')P('heavy'|'There was')P('rain'|'There was heavy')
``````

Each of the terms on the right hand side of this equation are n-gram probabilities that we can estimate using the counts of n-grams in our corpus. To calculate the probability of the entire sentence, we just need to lookup the probabilities of each component part in the conditional probability.

Unfortunately, this formula does not scale since we cannot compute n-grams of every length. For example, consider the case where we have solely bigrams in our model; we have no way of knowing the probability `P(‘rain’|‘There was’) from bigrams.

By using the Markov Assumption, we can simplify our equation by assuming that future states in our model only depend upon the present state of our model. This assumption means that we can reduce our conditional probabilities to be approximately equal so that

``````P('rain'|'There was heavy') ~ P('rain'|'heavy')
``````

More generally, we can estimate the probability of a sentence by the probabilities of each component part. In the equation that follows, the probability of the sentence is reduced to the probabilities of the sentence’s individual bigrams.

``````P('There was heavy rain') ~ P('There')P('was'|'There')P('heavy'|'was')P('rain'|'heavy')
``````

Applications#

What can we use n-gram models for? Given the probabilities of a sentence we can determine the likelihood of an automated machine translation being correct, we could predict the next most likely word to occur in a sentence, we could automatically generate text from speech, automate spelling correction, or determine the relative sentiment of a piece of text.