Describing a text by its words
A bag of words describes a text by counting how often each word appears and ignoring the order. TF-IDF (term frequency, inverse document frequency) goes one step further and gives more weight to words that are rare across texts.
With these two ideas a program can say which words a text is really about. Search engines and spam filters both start here.
By the end of this lesson
Note
I can count words and weight the ones that matter.
Key words
| Word | What it means |
|---|---|
| Bag of words | a text described by its word counts, with the order thrown away |
| Term frequency | how often a word appears in a text, as a share of its tokens |
| Document frequency | how many texts contain a word |
| Inverse document frequency | a number that is high for rare words and zero for words in every text |
| TF-IDF | term frequency multiplied by inverse document frequency |
The cells students fill in are left blank in this preview.
A bag of words keeps counts, not order
Imagine tipping the words of a text into a bag and shaking it. You can still count each word, but you can no longer say which came first.
In Python a dictionary does the job. Each word is a key and its count is the value. "The bus is late" and "Late is the bus" give the same bag.
Count the words in a text
text = "the bus is late the bus is full the train is late"
counts = {}
for word in text.split():
if word in counts:
counts[word] = counts[word] + 1
else:
counts[word] = 1
print(counts)
# Change the text. Which word has the biggest count now?
Count with the library's counter
docker exec jupyter python3 -c "from collections import Counter; print(Counter('the bus is late the bus is full'.split()).most_common(2))"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Count the words in one column
docker exec jupyter sh -c "cut -d, -f4 hires.csv | sort | uniq -c"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Term frequency makes texts of different length fair
A raw count favours long texts. A word appearing 3 times in a book means less than 3 times in a short note.
Term frequency divides the count by the number of tokens: the share of the text the word takes. 2 late in 4 tokens is 0.5. 2 late in 10 tokens is 0.2.
Compare a short and a long text
short = "late bus".split()
long = "the bus is late and the train is late too".split()
for tokens in [short, long]:
count = tokens.count("late")
print(len(tokens), "tokens,", count, "late, term frequency", round(count / len(tokens), 3))
# Make the long text longer. What happens to the term frequency?
Rare words say more about a text
The word "the" is in nearly every text, so it cannot tell texts apart. A rare word can.
Document frequency counts the texts that contain a word. Inverse document frequency is log10 of the number of texts divided by that count. It is 0 for a word in every text, and bigger for rarer words.
Work out two inverse values
docker exec jupyter python3 -c "import math; print(round(math.log10(4 / 2), 3), round(math.log10(4 / 1), 3))"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
TF-IDF multiplies the two
The TF-IDF weight of a word in a text is its term frequency times its inverse document frequency. A word scores high when it is common in this text and rare in the others.
The table works it out for the text "the bus is late and the train is late", from a set of four short texts.
Worked example: weights in one text
| Word | Count | Term frequency | Texts with it | Inverse | Weight |
|---|---|---|---|---|---|
| the | 2 | 0.222 | 4 of 4 | 0 | 0 |
| is | 2 | 0.222 | 4 of 4 | 0 | 0 |
| late | 2 | 0.222 | 2 of 4 | 0.301 | 0.067 |
| bus | 1 | 0.111 | 2 of 4 | 0.301 | 0.033 |
| train | 1 | 0.111 | 1 of 4 | 0.602 | 0.067 |
The cells students fill in are left blank in this preview.
A common mistake
Warning
Many people think the most frequent word is the most important one. The most frequent words are usually "the" and "is", which are in every text. A word matters when it is frequent here and rare elsewhere, which is what TF-IDF measures.
Going further
Four texts are a tiny collection. In a real collection of thousands, "and" would be in most of them and its weight would fall towards 0.
Add three more short texts to the set in the assignment. Which weights change, and why?