Before this book fits a single model, do something that sounds too simple to be scientific: take a large body of text, count how often each word occurs, and then stare at the counts. This is the cheapest experiment in natural language processing, since a few lines of shell script will do it, and it also produces one of the most consequential findings in the field.
Language is wildly and lawfully unbalanced, and every system we build afterwards either respects that imbalance or is quietly broken by it.
Run the experiment on any sizeable English corpus and the same picture appears, with a handful of words such as the, of, and, to and a taking a startling share of all running text.
The Brown corpus makes a good witness, and this chapter measures it
repeatedly. Every figure comes from
autograder/nlp_pipeline.py, which is the tokeniser and
fitting code Project 1 is graded against, so the numbers here are the
ones your own submission should reproduce.
Under it Brown holds tokens and distinct words, of which the alone accounts for per cent, and the ten most frequent words together for per cent.
A different tokeniser gives different totals. A stricter rule that
keeps only fully alphabetic tokens, discarding the digits and the
apostrophe forms that TOKEN_RE admits, drops
to
.
Neither count is wrong, and neither is comparable to the other, so state
the tokeniser whenever you state a count.
At the other end of the table something stranger shows up, because almost half of all distinct words occur exactly once. In Brown the figure is per cent, with per cent occurring twice or fewer. These singletons have a name, hapax legomena, which is Greek for “said once”, and their sheer abundance is the first sign that word frequency does not behave the way intuition expects.
Two clarifications before we go on, because the vocabulary of counting causes endless confusion. A token is a running occurrence of a word and a type is a distinct word, so the sentence “the cat saw the dog” has five tokens but four types, because the occurs twice. Everything in this chapter is a statement about how types and tokens relate.
Order the types by frequency, most frequent first, and give each one a rank, so that the most frequent word has rank 1, the next has rank 2, and so on.
George Kingsley Zipf did this in the 1930s, by hand and in heroic quantity, and he found that frequency and rank trade off almost exactly inversely:
where is the frequency of the rank- word and is a constant of the corpus.
Read literally, that says the second word is about half as frequent as the first, the tenth about a tenth as frequent, and the hundredth about a hundredth.
Take logarithms of both sides. Equation (3.1) becomes
which is with , , slope and intercept .
That is the whole trick, and it is worth learning once because it keeps returning. Plot frequency against rank on log log axes and the law becomes a check you can make by eye, since if the points lie on a line then the law holds and the steepness of that line is . Fitting the exponent is then ordinary least squares rather than curve fitting.
Every empirical law in this chapter is a power law, so every one of them becomes a line under logarithms, and so do the neural scaling laws of Chapter 18.
This is the most reproduced plot in corpus linguistics and you will draw it in Project 1, with dots hugging a descending line across three or four orders of magnitude, from the down into the fog of hapaxes.
The line is not perfect, and its imperfections are informative. At the very top the few most frequent words sit slightly off it, while at the bottom the singletons form discrete horizontal shelves, because a word can occur once or twice but never times.
Benoît Mandelbrot proposed a small correction that fits the head far better:
where the shift flattens the curve for the first few ranks.
How large comes out depends almost entirely on how much of the tail you fit, because is what absorbs the bend. On Brown:
| Rank range fitted | ||
|---|---|---|
| 0.9668 | 0.00 | |
| 1.0984 | 10.25 | |
| , all ranks | 1.5180 | 403.25 |
Fit the head alone and
comes out exactly zero, so Mandelbrot buys nothing and plain Zipf
already describes the head. Fit every rank, which is what
fit_mandelbrot does, and
runs into the hundreds.
A large is therefore not a verdict on your corpus but simply what a single power law needs in order to cover a curve that bends. Notice that climbs along with it, because both are absorbing the same curvature, so quote , and the rank range together or quote none of them.
Zipf’s own explanation for why language does this was a principle of least effort, where speakers want a small vocabulary of reusable words while listeners want a large vocabulary of precise ones, and the power law is where that tug of war settles.
Later work is a useful corrective, because surprisingly weak assumptions produce Zipf like curves, including random typing with a space bar. The law’s existence therefore tells us less than one might hope, while its consequences for us are concrete, and we return to them at the end of the chapter.
Reading a law off a plot is not the same as measuring it, so this section fits properly, on data you can check by hand.
The corpus is a collection of Indian budget speeches, and the frequency table gives fifteen rows covering ranks through and ranks through . The top word, the, occurs times, the word at rank occurs times, and the word at rank occurs times.
The first instinct is to solve for from two points, and dividing Equation (3.1) by itself at two ranks makes the constant cancel:
Now test that number where it was not fitted. Predicting rank gives against a measured , which makes the estimate per cent too high.
The fix is to stop throwing data away, so take logarithms and fit the line of Section 3.2.1 by least squares over all fifteen points:
That gives and , and the same test now predicts against , so the error falls from per cent to under .
These are exactly the values fit_zipf returns on the
same fifteen rows, so the procedure above is the graded one, not an
illustration of it.
| Method | squared error | |||
|---|---|---|---|---|
| Two points, and | 0.8136 | n/a | n/a | 695 |
| Least squares, all 15 points | 0.9426 | 0 | 0.0453 | 485 |
| Mandelbrot, scanning | 0.9843 | 0.5 | 0.0302 | 472 |
Table 1.1 adds Mandelbrot’s correction to the comparison. The shift sits inside the logarithm, so least squares cannot reach it, and the remedy is to scan , fit and at each value, and keep the best. That one extra parameter buys a third off the error.
Notice that the fitted is larger than the observed , so the line does not pass through the top word, and it should not. The head is flatter than the body, which means a fit dominated by the head understates , and that is exactly what the two point estimate did.
Now the warning promised earlier. The Mandelbrot fit is a two parameter optimisation with a shallow valley:
| best | squared error | |
|---|---|---|
| 0.0 | 0.9426 | 0.0453 |
| 0.5 | 0.9843 | 0.0302 |
| 1.0 | 1.0183 | 0.0356 |
| 2.0 | 1.0749 | 0.0643 |
Doubling moves by more than three per cent while barely moving the error, so report as a pair, because otherwise neither number means anything.
One more measurement settles what actually is. Fit Brown over different rank ranges and the answer moves:
| Rank range fitted | fitted |
|---|---|
| 0.9816 | |
| 0.9668 | |
| 1.0726 | |
| , all types | 1.3492 |
The tail falls faster than the head, so a wider window gives a steeper line, and that is why the textbook claim is safe: it is a statement about the first few thousand ranks and nothing more.
An exponent quoted without its fitting range is not a measurement, so report the range every time.
Equation (3.1) gives counts. Divide by the total count and it becomes a distribution over the vocabulary:
where is the generalised harmonic number.
That equation is usually read past, so it is worth slowing down. Zipf’s law assigns each rank a weight, , and weights are not probabilities, because nothing makes them sum to one and in general they do not.
is simply their total, so dividing every weight by it turns the weights into probabilities, since a set of numbers divided by its own sum always sums to one. Dividing changes no ratio between two words either, so the shape the law describes survives the normalisation untouched.
A vocabulary of eight with makes this concrete, and the weight of rank is then just .
| weight | running sum | ||
|---|---|---|---|
| 1 | 1.0000 | 0.3679 | 0.3679 |
| 2 | 0.5000 | 0.1840 | 0.5519 |
| 3 | 0.3333 | 0.1226 | 0.6746 |
| 4 | 0.2500 | 0.0920 | 0.7665 |
| 5 | 0.2000 | 0.0736 | 0.8401 |
| 6 | 0.1667 | 0.0613 | 0.9014 |
| 7 | 0.1429 | 0.0526 | 0.9540 |
| 8 | 0.1250 | 0.0460 | 1.0000 |
| 2.7179 | 1.0000 |
The second column sums to rather than to one, and that total is . The third column is the second divided by it, and now it does sum to one.
With that in hand, is the chance that a token drawn at random from the corpus is the rank word, and summing it gives the coverage of the top words:
The middle step is the whole derivation. Summing the first probabilities means summing the first weights and dividing by the same total, and a sum of the first terms is precisely what a harmonic number is, so the ratio is not a trick. The numerator is the mass you keep, the denominator is all the mass there is, and both are sums of the same terms.
On the toy vocabulary, the top two words hold , and the running sum column agrees, because it is the same arithmetic.
The normaliser also answers a question the previous section left open. What happens to coverage as the vocabulary grows?
| growth | |||
|---|---|---|---|
| 0.8 | 15.47 | 74.81 | 4.84 |
| 1.0 | 7.49 | 14.39 | 1.92 |
| 1.2 | 4.34 | 5.28 | 1.22 |
For the sum diverges, so a thousand times more vocabulary keeps adding to the denominator, the coverage of any fixed keeps falling, and the tail never becomes negligible however much text you collect. Above one the sum converges and the head holds a stable share no matter how large gets.
Measured for natural language sits close to one and usually just below it, which means language lives on the side of this boundary where the tail is permanent. That is the mathematical statement of a fact Heaps’ law states empirically in Section 3.5.1, namely that new words keep arriving forever.
One distinction has to be nailed down before the table below, because it is where the reading usually goes wrong. A type is a distinct word in the vocabulary while a token is a word as it occurs in running text, so the sentence the cat sat on the mat has six tokens and five types, because the appears twice.
Coverage counts tokens and the size of a vocabulary counts types. Those are different units, and the distance between them is the whole content of Zipf’s law, which is why a number like “two per cent of the vocabulary” and a number like “sixty-nine per cent of the text” can describe the same cut-off and still look nothing alike.
This is also why coverage is the useful form of the law. Raw counts depend on how much text you happened to collect, so two corpora cannot be compared with them, whereas and are fractions and can be. Coverage converts a curve into a budget, and that is what makes it the single most useful number in the chapter.
| Top types | per cent of | coverage, model | coverage, measured |
|---|---|---|---|
| 10 | 0.02 | 22.51 | 24.09 |
| 100 | 0.23 | 41.40 | 47.18 |
| 1,000 | 2.26 | 62.14 | 69.13 |
| 10,000 | 22.56 | 84.56 | 92.60 |
Read column two against column four of Table 1.2. About two per cent of the vocabulary carries about per cent of the running text. Equivalently, discarding the rarest per cent of the types costs under eight per cent of the tokens.
The model tracks the measurement closely at the head and drifts at the tail, for the reason the previous section gave, since one cannot bend twice.
Three later decisions rest on this table. A stop list is short because the head is short, a truncated vocabulary loses many types and few tokens, and a subword vocabulary of pieces spends its whole budget on the head, with Chapter 5 showing what it does with the rest.
One caveat is worth keeping in view. When the sum grows without bound as grows, so the tail never becomes negligible however much text you add.
Zipf’s law describes a frozen corpus, whereas Heaps’ law describes what happens as a corpus grows.
Let be the number of tokens read so far and the number of distinct types seen. Empirically,
with usually between 10 and 100, and the exponent usually quoted between and for English.
Quote the two together, because they are coupled. A fit that raises must lower to pass through the same data, so a large always arrives with a small . Pin on Brown and watch the best move with it:
| pinned at | best |
|---|---|
| 0.40 | 155.93 |
| 0.50 | 43.17 |
| 0.60 | 11.95 |
| 0.5764 | 16.18 (both fitted freely) |
So “ between 10 and 100 and between 0.4 and 0.6” is one statement about a curve rather than two independent ones. Brown measures and in Section 3.5.1, while Figure 1.2 shows a smaller and more homogeneous corpus at with under two. That figure is right, because small corpora really do fit that high.
Two properties matter here. First, the exponent is less than one, so vocabulary growth decelerates, which means the second million tokens bring fewer new words than the first million did and doubling a corpus does not come close to doubling its vocabulary.
Second, and this is the part with teeth, the function never flattens, because a power law has no asymptote and there is no corpus size at which stops growing. However much text you collect, the next document can still hold a word you have never seen, whether a name, a typo, a coinage, a chemical formula or a hashtag. The vocabulary of a natural language is not a closed set, and any system built around a fixed word list has already decided to fail on the tail.
You will check both properties in Project 1 by plotting as your corpus streams past, and in the spirit of Section 3.8 below you will predict the curve’s shape before you draw it.
Equation (3.7) linearises the same way Zipf’s law did:
So is a slope, and it is also an elasticity, because doubling the corpus multiplies the vocabulary by . At , four times the text gives twice the vocabulary.
Sample the vocabulary every
tokens, which is what fit_heaps does, and fit all
points. Five of them:
| tokens | types | |
|---|---|---|
| 1,000 | 468 | 0.4680 |
| 10,000 | 2,584 | 0.2584 |
| 100,000 | 12,962 | 0.1296 |
| 500,000 | 31,854 | 0.0637 |
| 1,000,000 | 43,648 | 0.0436 |
The fit gives and . The corpus grew by a factor of a thousand while the vocabulary grew by a factor of .
Fitting the full curve matters, because least squares on five hand-picked marks gives a visibly different pair and would not agree with the grader.
Now for the experiment that matters more. Fit the law on the first tokens only and use it to predict a corpus ten times larger, where that prefix gives and , so
One decade of extrapolation, per cent too many types.
The cause is the same concavity that moved earlier, because the exponent is not a constant of the language either and drifts downward as grows as the log log curve bends gently. Fit over the range you will actually operate in, and treat any extrapolation as an upper bound.
That the error is an over-estimate is worth noticing, since it is the safe direction for sizing an embedding table and the wrong direction for a cost estimate.
The two laws are not independent observations. If frequency falls as , then a word at rank needs roughly tokens of text before it appears at all. Reading that backwards, tokens reveal about distinct types, so
Brown fitted over all ranks gives , so Equation (3.9) predicts against a measured of . That is the right order of magnitude from two unrelated measurements, and not much better than that.
They do not agree exactly, and they should not, because the derivation assumes a single holds across the whole rank range and Section 3.3 showed that it does not. The lesson is the relationship rather than the decimal places: steeper frequency decay means fewer rare words, which in turn means slower vocabulary growth.
A natural summary of lexical richness is the type token ratio
which is vocabulary size divided by text length. Rich, varied prose should score high and repetitive, formulaic text should score low, and on the whole it does.
There is a trap, though, and Heaps’ law describes it exactly. Since with , we get , which falls as grows.
Take a 1,000 word essay and a 100,000 word novel by one author, and their TTRs will differ wildly, with the novel’s far lower, for no stylistic reason whatever. TTR is a property of a text at a length, never of the text alone.
Brown’s own fit, and , puts numbers on that:
| predicted TTR | measured TTR | |
|---|---|---|
| 1,000 | 0.8673 | 0.4680 |
| 10,000 | 0.3270 | 0.2584 |
| 100,000 | 0.1233 | 0.1296 |
| 1,000,000 | 0.0465 | 0.0436 |
Same author, same style, four different answers, and the measured column is the one that matters, falling by a factor of ten.
The first row is worth pausing on, because the fitted law is good near a million tokens and poor at a thousand, since the log log curve is concave and points pull the line towards the large end. A fitted law is a summary of a curve rather than an oracle for every point on it.
Table 1.3 runs the experiment on six genres of Brown. The raw column uses the whole genre. The standardised column cuts each genre into non-overlapping windows of tokens, computes TTR in each, and averages them.
| Genre | raw TTR | rank | std. TTR | rank | |
|---|---|---|---|---|---|
| press reportage | 90,089 | 0.1359 | 3 | 0.3077 | 1 |
| humour | 18,450 | 0.2552 | 1 | 0.3021 | 2 |
| general fiction | 58,605 | 0.1458 | 2 | 0.2744 | 3 |
| romance | 58,966 | 0.1307 | 4 | 0.2520 | 4 |
| learned | 164,036 | 0.0885 | 6 | 0.2478 | 5 |
| government | 63,214 | 0.1106 | 5 | 0.2320 | 6 |
Raw TTR crowns humour as the richest genre in Brown, and humour is also the shortest genre in Brown, at tokens against for learned prose. The measurement is reading length rather than style.
Two rankings actually reverse. Raw TTR puts fiction above press reportage, while on equal windows press reportage wins, and raw TTR puts government above learned prose, while on equal windows learned prose wins. Neither reversal is noise, because both hold at every window size from tokens up to .
The discipline that follows is simple and not negotiable. Never compare type token ratios across samples of different sizes. Compare equal length slices instead, or use a length corrected variant.
The measure used in Table 1.3 is the mean segmental type token ratio. Cut the text into windows of fixed size and average:
It is simple and it works, and its weakness is that the answer still depends on , so must be reported and held fixed across everything being compared.
A cheaper variant is the root type token ratio, , which is Equation (3.7) with forced to , and it only removes the length effect where really is near . Brown’s is , close enough to make the shortcut tempting and far enough to bias a comparison.
The honest summary of lexical richness is neither of these. It is the fitted pair from Section 3.5.1, which describes the whole curve rather than one point on it.
Project 1 asks you to compare your corpus against a contrast genre, and it fixes the sample size for exactly this reason. When the measured TTRs still differ, the difference is real, because legal boilerplate and technical templates repeat themselves and fiction does not.
These three regularities look like curiosities, but they are the standing constraints under which every model in this book operates.
The laws also price the preprocessing decisions of Chapter 2. Measured on Brown, each figure a share of the raw counts:
| Operation | tokens left | types left |
|---|---|---|
| Stop words removed | 55.5% | 99.8% |
| Numbers stripped | 99.0% | 97.5% |
| Porter stemming | 100.0% | 65.4% |
| Drop every type seen times | 94.1% | 28.0% |
Read the two columns against each other. Stop word removal takes per cent of the tokens and per cent of the types, which is Zipf’s law stated as an engineering fact, because stop words are very few types carrying very many tokens.
Stemming is the mirror image, leaving every token where it is while per cent of the vocabulary collapses.
Dropping every type seen five times or fewer removes per cent of the vocabulary and costs per cent of the tokens, which is the trade Table 1.2 priced and why a fixed subword vocabulary is less of a sacrifice than it looks.
One thing barely moves at all. The Heaps fit goes from , to , once stop words and numbers are gone, so the curve is a property of the language rather than of your cleaning.
Try it yourself.
code/worked_examples/empirical_laws.pyprints every fit and table in this chapter.python3 empirical_laws.py harmonicbuilds the normaliser on a vocabulary of eight, where every division can be checked on paper, and then shows diverging at .python3 empirical_laws.py mandelbrotshows climbing from to as the fitting range widens.python3 empirical_laws.py heapspins and watches move, then extrapolates a decade and misses by per cent.
The head motivates weighting. The most frequent words are overwhelmingly function words, and glue like the and of appears everywhere and so distinguishes nothing. Any similarity measure built on raw counts will be dominated by exactly the words that carry least content, which is the problem inverse document frequency solves in Chapter 4. At bottom, tf-idf is a machine for discounting the Zipfian head.
The tail motivates smoothing. Roughly half the vocabulary occurs once, and the exact fraction depends on corpus size, rising as the corpus shrinks. Full Brown gives per cent, its news genre per cent and its science fiction per cent, and at any of those figures reliable statistics exist for almost no specific word. Events unseen in training are the normal case. That is why the zero probability problem of Chapter 10 is the central difficulty of statistical language modelling, and why no amount of patching corner cases will address it. Every model, up to the largest LLM, must reserve belief for the unseen.
Heaps’ law motivates subwords. If the vocabulary never
closes then a word level system meets out of vocabulary items forever,
and mapping them all to one <unk> symbol, as in
Chapter 10, throws their identity away.
The modern answer is to decompose rare words into pieces that
are in a closed set. That is the next chapter, and it is best
read as a direct engineering response to Equation (3.7).
This chapter closes with a habit rather than a law.
Every quantitative claim above is checkable in minutes on any corpus you can lay hands on, whether the slope near , the exponent near , or the falling TTR. This course will repeatedly ask you to predict the number before you measure it.
The point is not ritual. A prediction forces your mental model into the open where the measurement can correct it, whereas a measurement taken with no prediction slides past the mind and teaches nothing.
Calibration is knowing how far off your guesses tend to be, and it is a trainable skill as well as the difference between a practitioner who understands a system and one who merely operates it.
We start training it on word counts because word counts are cheap, and by the end of the book you will be predicting perplexities, attention patterns and retrieval failures the same way.
Zipf (1949), Human Behavior and the Principle of Least
Effort, is still a strange and rewarding read. Manning and Schütze
(1999) give the sober statistical treatment of both laws. Baayen (2001)
is the modern reference for the mathematics of the tail. Both laws can
be fitted in one line with numpy.polyfit or
scipy.optimize.curve_fit, and the last exercise below is
there because one line is enough to fit the wrong thing.
Fit Zipf. Take a corpus of your choice. A novel from Project Gutenberg is ideal. Rank the word types by frequency, plot frequency against rank on log log axes, and fit the exponent of Equation (3.1). Report . Say where the fit is worst, in the head, the tail, or both.
Fit twice, on purpose. Estimate from ranks and alone, using the two point formula of Section 3.3. Then estimate it by least squares over ranks . Predict with each and compare against the measured value. Report both signed errors.
Report the range. Fit over ranks , and all ranks. Give the three numbers in a table. Explain in one sentence why the widest range gives the steepest line.
Mandelbrot’s correction. Refit the head of the same distribution with the two parameter form of Equation (3.3) and report . The chapter warns that this fit is a shallow valley. Report the pair together, and show that a range of values fit almost equally well.
Coverage, predicted and measured. Compute the coverage of the top , and words directly from your counts. Then predict the same three numbers from Equation (3.6) using your fitted . Where does the model diverge from the measurement, and why?
The cost of a cut-off. Using your coverage numbers, find the vocabulary size that keeps per cent of the tokens. What fraction of the types does it discard? Relate your answer to the fixed vocabulary of Chapter 5.
Trace Heaps’ law. Stream the corpus token by token. Record the vocabulary size against the token count , then fit the exponent of Equation (3.7). Does vocabulary growth ever stop? Connect your answer to the pressure that motivates subword tokenisation in Chapter 5.
Extrapolate and fail. Fit Heaps’ law on the first tenth of your corpus, predict for the whole of it, then measure. Report the signed error. Is your prediction too high or too low, and does the sign agree with the chapter?
Check the link. Take your fitted over all ranks and your fitted . How close is to ? Give one reason the agreement is not exact.
Type token ratio across genres. Compute the TTR of your corpus and of a second corpus from a different genre, first raw and then on equal length samples. Report whether the ranking changes. Explain in one sentence why the equal length constraint is not optional.
Choose the window. Compute the MSTTR of Equation (3.11) at , and on the same two corpora. Do the values change? Does the ranking change? Say what that implies about reporting a single MSTTR.
Predict first. Before running any of the above, write down three things. Your predicted . Your predicted Heaps’ exponent. Which genre you expect to have the higher TTR. Compare with your measurements and account for each surprise. This is the discipline of Section 3.8.
Where you fit changes what you get. Fit Equation (3.1) to the fifteen budget speech
points twice with scipy.optimize.curve_fit. Fit it once to
against
,
and once to the power law itself in linear space, with no logarithms
anywhere. The first returns
,
the figure this chapter reports, and the second returns
.
Work out which of the fifteen measurements the second fit is really
listening to, and then add the space you fitted in to the list of things
Section 3.8 says you must report
alongside an exponent.
Each one reproduces the tables above. Open it in Colab, change an input and watch which numbers move.
empirical_laws.pyZipf and Heaps, fitted
Fitting both laws to real rank counts, the coverage curve, and the length trap that makes type token ratio misleading.
standard library only Run it in Colab Notebook SourceFrom Natural Language Processing: From Corpus Statistics to Grounded LLMs, by Ramaseshan Ramachandran.