Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

Cosine similarity between texts

After this lesson: I can measure how similar two texts are.

55 min lesson2 commandsJupyterLab data science lab: pandas, Matplotlib and scikit-learn in the browser

How alike are two texts?

Cosine similarity is a number from 0 to 1 that says how alike two texts are. It compares the direction of their word-count vectors, so a long text and a short one about the same thing still match.

A search engine uses an idea like this to rank pages against your query. You will build it from a list of numbers.

By the end of this lesson

Note

I can measure how similar two texts are.

Key words

WordWhat it meansExample
Vectora list of numbers[2, 1, 0]
Vocabularythe fixed list of words that sets the order of a vector
Dot productmultiply two vectors place by place, then add
Lengththe square root of a vector multiplied by itself
Cosine similaritythe dot product divided by the two lengths

The cells students fill in are left blank in this preview.

A text becomes a vector of counts

To compare texts with arithmetic, turn each one into a vector, a list of numbers. First fix a vocabulary, a list of words in a set order. Then count each word of the vocabulary in the text.

Both texts use the same vocabulary, so place 1 of each vector means the same word.

Turn a text into a vector

Code: python
vocabulary = ["bus", "late", "exam", "monday", "library"]
text = "the bus is late the bus is full"
counts = []
for word in vocabulary:
    counts.append(text.split().count(word))
print(counts)
# Change the text to "the exam is on monday". What are the counts now?

Worked example: three texts as vectors

Textbuslateexammondaylibrary
A: the bus is late the bus is full21000
B: the exam is on monday00110
C: the bus is late today11000

The cells students fill in are left blank in this preview.

The dot product measures overlap

The dot product multiplies two vectors place by place and adds the results. A place where both have the word adds a positive number. A place where one has 0 adds nothing.

A and C: 2 times 1, plus 1 times 1, plus zeros, makes 3. A and B share no word, so their dot product is 0.

Cosine similarity divides by the lengths

A long text has a big dot product just for being long. To remove that, divide by the two lengths. The length of a vector is the square root of its dot product with itself.

A has length the square root of 5, about 2.236. C has the square root of 2, about 1.414. So 3 divided by 2.236 times 1.414 is 0.949: very alike.

Work out the cosine of A and C

Command
docker exec jupyter python3 -c "import math; a=[2,1,0,0,0]; c=[1,1,0,0,0]; print(round(sum(x*y for x,y in zip(a,c))/(math.sqrt(5)*math.sqrt(2)),3))"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Work out the two lengths

Command
docker exec jupyter python3 -c "import math; print(round(math.sqrt(5), 3), round(math.sqrt(2), 3))"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write cosine similarity as a function

Code: python
import math

def cosine(a, b):
    top = 0
    for n in range(len(a)):
        top = top + a[n] * b[n]
    return top / (math.sqrt(sum_squares(a)) * math.sqrt(sum_squares(b)))

def sum_squares(v):
    total = 0
    for x in v:
        total = total + x * x
    return total

print(round(cosine([2, 1, 0, 0, 0], [1, 1, 0, 0, 0]), 3))
print(round(cosine([1, 2], [2, 4]), 3))
# Try [1, 0] and [0, 1]. What does the answer mean?

A common mistake

Warning

Many people think a cosine of 1 means two texts are identical. It means the words appear in the same proportions. "bus late" and "bus late bus late" score 1, and so do two texts that use the same words in a different order.

Where the number is used

Turn a search query into a vector, compare it with every page, and show the highest cosines first. Compare a new support ticket with old ones to find a likely answer.

Counts can be replaced by TF-IDF weights, so rare words count for more. The method does not change.

Going further

Write three short texts about your own week and put them in a table like the one above. Work out which two are the most alike, by hand, then check with the function.

Then explain why two texts can score 1 while meaning opposite things, such as "the bus is late" and "the bus is not late".

About this lab and its source: JupyterLab data science lab: pandas, Matplotlib and scikit-learn in the browser

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.