Zipf's Law
Words by the Numbers
Chapter 2 ยท Zipf’s Law
Words by the Numbers 1 ended with a hint: in a tiny passage the commonest words were small grammatical ones, and most other words appeared once. This chapter asks how steep that drop is. The surprise, noticed by the American linguist George Kingsley Zipf, is that the drop follows a simple pattern across very different texts, and a few lines of arithmetic and Python are enough to see it, measure it and, importantly, to see where it stops working. The maths is light: division, a logarithm, and a line of best fit that Python computes for you.
pydoc_data.topics module): about 75,000 tokens of technical English, available on any machine, but not typical English prose, and its counts change a little between Python versions. Background facts come from web searches that returned summaries of encyclopedia and paper pages; such fetched pages are often truncated or model-summarised, so treat the wording as a paraphrase. The sources agree on the basic statement and the Brown Corpus figure but differ on exact numbers and framing (conflict; check). The vocabulary size and text length in the first snippet are assumed, illustrative numbers. Statements marked (check) were not confirmed against a source.
Rank and Frequency
Sort the types of a text by how often they occur: the commonest gets rank 1, the next rank 2, and so on. Zipf’s law, as the sources summarise it, says that the frequency of a word is roughly inversely proportional to its rank. The word of rank 2 should occur about half as often as the word of rank 1, rank 3 about a third as often, rank 10 about a tenth. Written as a formula, with f the frequency and r the rank, f ≈ C ÷ r, where C is a constant for the text. Another way to say it: rank × frequency stays roughly constant. Zipf set out the idea at length in his 1949 book on the “principle of least effort”, which argued that speakers and listeners both try to save effort (this is the reference accounts’ summary; check against the book).
Here is what a perfect 1/rank text would look like. The snippet assumes a vocabulary of 1,000 types and 100,000 tokens; both numbers are illustrative, chosen only to make the arithmetic easy to follow.
The last column never changes: that is the whole law. The constant 13,359 is simply the number of tokens divided by the harmonic sum 1 + 1/2 + 1/3 + … + 1/1000 (about 7.485), so rank 1 takes 13.4% of the text. Real texts only approximately follow this, as the next section shows.
Testing It on Real Text
Now the same table for real text. The snippet tokenises the whole Python reference documentation with the tokeniser from Words by the Numbers 1 and prints the top ten ranks with their rank × count products.
The top word, the, takes 5,201 of 75,022 tokens, which is 6.9%. For comparison, the sources report that in the Brown Corpus, a one-million-word sample of American English from the 1960s, the is also the commonest word and accounts for nearly 7% of all occurrences (69,971 out of slightly over a million; second-hand figures, check). The rank × count column wobbles between about 4,400 and 8,700 in the top ten, so the product is not constant, but it stays within a factor of two, over a range of counts from 5,201 down to 760. That is why people say “Zipf’s law” for something this loose. Note also the bottom line of the output: 918 of the 3,445 types (27%) occur exactly once. That crowd of rare words is the long tail.
| Part of the curve | Ranks (this text) | What lives there |
|---|---|---|
| Head | 1 to about 10 | grammar words: the, a, is, of |
| Body | about 10 to several hundred | common content words and technical terms |
| Long tail | hundreds to 3,445 | rare words; 918 appear once |
Log-Log Plots and the Slope
If f = C ÷ r, take logarithms: log f = log C − log r. So on a plot with log rank across and log frequency up, a Zipf text is a straight line with slope −1. A log-log plot turns a curve that plunges and then crawls along the floor into something the eye can judge. Python can fit the line without a plotting library. The snippet below uses the standard least-squares formula, then draws a crude text-mode picture in which each bar’s length is ten times the base-10 logarithm of the count.
The slope over the top 1,000 ranks is −1.04, close to the textbook −1, while over only the top 100 ranks it is −0.81. The same text gives different slopes depending on which ranks you fit, so a slope is always quoted together with the rank range. In the picture, each doubling of rank takes the count down by a factor that is not quite two at the left (5,201, 2,188, 1,561) and somewhat steeper later (95, 52 at ranks 128 and 256), which is a straight-ish line on log axes with a gentle bend. The usual fix in the literature is the Zipf–Mandelbrot form, which has frequency proportional to 1/(rank + b)a, with two adjustable numbers instead of one; the sources attribute it to Benoit Mandelbrot (check the details).
| Form | Frequency at rank r | Straight line on log-log? |
|---|---|---|
| Zipf (simple) | C ÷ r | yes, slope −1 |
| Generalised | C ÷ ra | yes, slope −a |
| Zipf–Mandelbrot | C ÷ (r + b)a | bends at low ranks, straight later |
Does Text Length Matter, and Is It Special to Language?
Two honest tests. First, fit the same text at different lengths, and add a second, quite different text: the doc-strings of Python’s built-in names (a few thousand tokens).
With only the first 1,000 tokens the slope is −0.90; at 10,000 it is −1.15; at 40,000, −1.06; and for the full text, −1.04. Short samples are noisy, so do not judge the law from a paragraph (the 70-word passage from Words by the Numbers 1 has far too few repeats). The small doc-string collection gives −0.93 over its top 300 ranks, and its top word is again the. These are two samples of one narrow genre; they say nothing about novels or speech.
The second test is a famous deflation. The psychologist George Miller pointed out in 1957 that text typed by a monkey hitting random keys, including the space bar, also yields a power law; Wentian Li gave a formal argument in 1992 (the sources agree on this core story, but differ on how to credit Miller, Mandelbrot and Li; conflict; check). The snippet below does the experiment with a fixed random seed: one million random characters from 26 letters and the space, all equally likely.
The monkey text has 35,637 “words” of which 33,591 are different, and the fit over the top 1,000 ranks gives −0.73, not −1. Its curve is a staircase, because all words of the same length are equally likely, so many types tie on the same count. Short words are common simply because there are fewer of them to type. The lesson is not that the law is meaningless but that a straight line on log-log axes is a weak test: judge a claim by its slope, its rank range and how much data lies behind it, and ask what a random-text control gives.
| Text | Tokens | Top-1000 slope |
|---|---|---|
| Python documentation | 75,022 | −1.04 |
| Monkey typing (seed 1) | 35,637 | −0.73 |
| Built-in doc-strings | 4,908 | −0.93 (top 300) |
Build a rank–frequency table for a short invented passage and print rank × count for the top eight ranks. How many types share the lowest count, and what does that do to the shape of the tail?
๐ View solutionPredict the counts at ranks 1, 2, 5, 10, 50, 100, 500 and 1,000 with the ideal 1/rank formula, using the real text’s own token and type totals, and print the ratio of actual to predicted. Where does the simple law over-predict, and where under-predict?
๐ View solutionFit the log-log slope separately over the rank bands 1–10, 10–100, 100–1,000 and 1,000–2,000, and count the types with frequency 1. In which band does a single straight line stop being a good description, and why?
๐ View solutionQuick Reference
- Rank: position in the list sorted by frequency, commonest = 1
- Zipf’s law: frequency ≈ C ÷ rank, so rank × frequency is roughly constant
- Log-log plot: log rank against log frequency; a straight line of slope −1 means Zipf
- Long tail: many rare words; in a 75,022-token text, 27% of the types occurred once
- Zipf–Mandelbrot: adds an offset b to the rank so the head can bend
- Random-text control: monkey typing also gives a rough power law, so check slope, range and data size
- Python habit:
sorted(Counter(tokens).values(), reverse=True)gives the frequencies by rank