Random Indexing
Counting every possible word-context pair can require a very large table. Random indexing gives contexts small random vectors and accumulates them, keeping the representation a fixed size as new examples arrive.
12 sections · 10 questions · 4 coding challenges
The arrow keys move between sections too.
Could We Build Context Vectors Without Storing the Whole Table?
BOTIE
Kanerva, Kristoferson and Holst's 2000 random-indexing work proposed using sparse random index vectors for contexts. Word representations could then be built by accumulating the index vectors of the contexts in which the words occurred.
Each context receives a short random signature with only a few nonzero entries. A word adds the signatures of its observed contexts. Words with similar context histories therefore accumulate similar patterns, without reserving a separate coordinate for every context. The random signatures make an approximate representation possible; they do not assign linguistic meaning in advance or preserve every original count exactly.
Keep a Sketch Instead of the Whole Count Table
A word-context table can become enormous. Most entries may be empty, yet storing a separate coordinate for every possible context still makes the representation wide.
Random indexing gives each context a short, fixed numerical signature. A word accumulates the signatures of contexts in which it appears.
Start with the evidence we want to keep
If bread appears near oven and bake, we want its representation to record those observations. A full table would reserve separate places for oven, bake, and every other possible context.
Target word
- bread
Observed contexts
- oven
- bake
Random codes become informative through observed use
The detailed example constructs the signatures, accumulates them, and compares the resulting word vectors.
The signatures remain fixed. The corpus determines the accumulated word representations, so random initialization and learned distributional evidence have different roles.
Explore the full example
Follow which context vectors are added for one word. Compare the resulting neighbours at different widths and random seeds.
…
Part 1. The Table That Only Exists To Be Thrown Away
1. Twenty-four documents, and three sentences small enough to check
Everything on this page is fitted to one of two collections, and it is worth knowing what is in them before any method touches them. The larger one is twenty-four documents, twelve about cooking and twelve about sailing. The cooking half is written from ten words, flour, sugar, butter, eggs, oven, bake, stir, whisk, dough and pan; the sailing half from ten of its own, sail, wind, boat, harbour, anchor, tide, mast, rope, deck and crew.
No subject word appears in both halves. What the halves share is three words carrying no subject at all, and, the and we, and each document uses exactly one of them.
Each document is six words long, five consecutive words of its own half taken in a cycle and one of the three shared words, which comes to 144 word occurrences over 23 distinct words. The arrangement is deliberate, since it makes every word of a half keep the same company as every other word of that half, and so makes the two numbers this page keeps reporting mean something.
The smaller collection is three sentences of three words each, the cat sat, the dog sat and the cat ran. Five distinct words, and every number it produces can be checked by hand, which is what Part 2 uses it for.
Keep in mind
2. Counting which word turned up beside which
The starting point for every counting method is the same table. Write down one row for each distinct word and one column for each distinct word, and in the cell where a row and a column meet, put how often those two words turned up within a few positions of each other. How few is the window, and five positions on each side is the usual choice; a sentence boundary stops the reach, so nothing outside a document is ever company for anything inside it.
Every pair is counted from both ends, so the table is the same read either way round, and a word’s row and its column hold the same numbers. On the twenty-four documents the row of flour totals 30 and the rows of and, the and we total 40 each, which is a fact Part 4 comes back to.
Three sentences, two positions each side
Take the cat sat, the dog sat and the cat ran, and count everything within two positions. In the first sentence the is beside cat and two from sat, cat is beside both, and sat is beside cat and two from the. Do that for all three and the row of the reads 0, 2, 2, 1, 1 against the vocabulary in the order the, cat, sat, dog, ran.
The row of cat reads 2, 0, 1, 0, 1, and the row of ran reads 1, 1, 0, 0, 0. Twenty five cells for five words, and the whole thing fits on a line.
Keep in mind
3. Most pairs of words never once met
It would be reasonable to expect a table of who appeared beside whom to be useful only for pairs that did appear beside each other. It is not, and the reason is the whole point of counting. Two words that never met can still be recognised as alike, because what is compared is not the cell where they meet but their two rows, and two words that keep the same company have similar rows whether or not they ever shared a document.
On the twenty-four documents, 110 of the 190 pairs made of two subject words never once appeared in the same document. Flour and bake are one such pair, and their cell in the table holds exactly 0. Compare their rows and the answer is 0.7551, which is higher than any pair flour actually did meet. The nearest word to flour, by the table, is a word it was never once seen beside.
Keep in mind
4. The widest thing in the calculation is the thing nobody wants
A row per word and a column per word means the table has as many numbers as the square of the vocabulary. On the twenty-four documents that is 23 by 23, or 529 numbers. But nobody wants 23 numbers a word. The whole family of counting methods squeezes that row down to a handful of coordinates before anybody uses it, and at 16 numbers a word the answer holds 368.
numbers in the table = V × Vnumbers in the answer = V × dConstructing the full co-occurrence representation before reducing it allocates more coordinates than the final vectors retain.
temporary-to-final width ratio = vocabulary size / embedding width
example ratio = 23 / 16 ≈ 1.44The ratio is small on this toy corpus. It grows when the vocabulary grows while the requested embedding width stays fixed.
In a model
Keep in mind
Part 2. A Direction For Every Word
5. Give every word a direction, drawn before a word is read
The trick starts somewhere that looks unpromising. Give every word in the vocabulary a fixed list of numbers of exactly the width the answer is wanted at, drawn at random, and having nothing whatever to do with what that word means or where it appeared. Almost all of the entries are zero. A few positions are picked at random without repeating, half of them are set to +1 and the other half to −1.
At the width this page works in, that is 16 numbers of which 4 are anything at all. The direction drawn for flour is non-zero at positions 5, 7, 8 and 9 and zero at the other twelve. Draw again with a different starting point and every one of those numbers changes, and nothing about the collection has moved.
…
Keep in mind
6. A word’s position is the sum of the directions it was seen beside
Now read the collection once, straight through. Every time a word appears, look at the words within the window on either side of it, and add each of their directions onto a running total kept for the word in the middle. When the reading finishes, the running total is that word’s position, and it is as wide as a direction was, which is the width that was asked for.
position(word) = Σ over every occurrence Σ over every neighbour weight(distance) × direction(neighbour)Two words that keep the same company add up the same directions and land near each other, and neither of them ever needed a row of its own in anything. That is the whole of the method, and the rest of this page is spent on why the sum does not turn into a smear and on how far its answer falls from the one the table of counts would have given.
…
Cat, over three sentences
Cat appears twice, in the cat sat and in the cat ran, and with a window of two positions it has four neighbours in all. Adding the direction of the gives 0, 0, 1, −1, −1, 0, 1, 0. Adding sat next cancels the −1 in the fifth position and leaves 0, 0, 1, −1, 0, 1, 0, −1.
The second sentence contributes the again and then ran, and the total finishes at 0, 1, 2, −3, 0, 0, 1, −1, which is exactly what the fit reports as the position of cat. Four additions of eight numbers each, and no table of any kind was written down.
Keep in mind
7. Nothing is fitted and nothing is decomposed
It is worth pausing on what is absent. There is no objective being minimised, so there is no learning rate and no question of whether the walk has converged. There are no eigenvectors, so no decomposition has to be run and nothing has to be reordered by how much it accounts for. There is no second pass over the collection.
The only randomness in the whole procedure is the draw of the directions, and that happens before the first word is read. Fix the draw and the answer is fixed, exactly, down to the last bit, however many times it is run.
The work is easy to count. On the twenty-four documents there are 144 word occurrences, and at a window of five positions each side there are 720 occasions where one word is inside another’s window. Each of those adds a direction with 4 non-zero entries, so the whole reading is 2,880 updates to a single number, and nothing else happens.
In a model
8. One pass, or one multiplication
There is a second route to the same positions, and it is the route that says what the method actually is. Instead of walking the collection, build the table of counts from Part 1, stack the drawn directions into a block with a row per word, and multiply the two together. A word’s row of counts says how many of each other word’s direction to add, so the multiplication and the walk are the same additions in a different order.
positions = counts × directionsSo a position is a word’s row of the table, projected from as many numbers as there are words down to as many numbers as were asked for, by a random map. That is what makes this a projection of the table rather than a rule of thumb that happens to work, and it is why the geometry in Part 3 applies to it at all.
…
Measured on the three sentences, and on the twenty-four documents as well, the two routes agree exactly and the largest disagreement anywhere in the answer is 0, since every weight involved is a number binary holds exactly. Move to the twenty-four documents and let a neighbour further away count less, so that a weight of a third appears, and the largest disagreement becomes 8.88 × 10⁻¹⁶ in a table whose largest entry is 11.25, which is rounding and not a difference of method.
Keep in mind
9. What the fit answers on the twenty-four documents
Sixteen numbers a word, four of them non-zero in each drawn direction, one reading of the collection. Two words of one subject come out at 0.6399 on average and a word of each subject at 0.1247, and the two halves were never named to it. The whole table of counts, read directly and never squeezed, answers 0.6629 and 0.1192 to the same two questions.
Asked which words are nearest to flour, the fit answers eggs at 0.7909, butter at 0.7285, bake at 0.7130, whisk at 0.7017, pan at 0.7003 and sugar at 0.6270. All six are cooking words, and the six words it puts furthest away, anchor, tide, wind, boat, harbour and sail, are all sailing words. The playground at the top of this page is that fit, with the width, the draw and the counting rule left open.
Keep in mind
Check yourself
Questions on Parts 1 and 2
Question 1 of 5
By the table of counts, the word nearest to flour is one it was never once seen beside.
Part 3. Why Adding Up Directions Does Not Turn To Mush
10. Two random directions in many dimensions barely overlap
The obvious objection to Part 2 is that the additions must interfere. Twenty-three words are being added into positions only sixteen numbers wide, so there is not enough room for each word to have a place of its own, and every position ought to end up as a smear of everything.
The reason it does not is a fact about high-dimensional space that is hard to believe from low-dimensional experience. Two directions drawn at random are nearly at right angles to each other almost all of the time, and the more numbers they have the more nearly. Being at a right angle is exactly the condition for one to contribute nothing to a reading of the other, so adding a great many of them together leaves each one still recoverable, up to a little interference.
Drawing two hundred directions at once and measuring all 19,900 pairs of them, at 50 numbers each the mean size of the overlap is 0.0744 and 71.8% of the pairs are at exactly a right angle. At 500 numbers it is 0.0077 and 96.9%. Neither is a bound or an average over some assumption, it is what the draw produced.
Keep in mind
11. The rule that predicts it, and where it stops predicting
The rule behind those numbers is short. Two directions with n non-zero entries scattered over d positions share about n squared over d positions on average. Each shared position contributes plus or minus one to a reading whose natural size is n, so the expected size of the overlap is about n over d.
expected overlap ≈ n / dAt four non-zero entries in fifty positions that says 0.0800 and the measurement is 0.0744; at five hundred positions it says 0.0080 and the measurement is 0.0077. Those are close enough that the rule is worth carrying around.
It stops being worth carrying at both ends, and I would rather report where than let it be quoted where it fails. At eight positions it predicts 0.5000 and the measurement is 0.2994, which is a ratio of 0.5988, so it overstates the interference by nearly half at the narrow end. And if the directions are allowed to fill up instead of staying sparse, it collapses entirely. At fifty positions with all fifty filled it predicts 1.0000, meaning every pair should lie on top of every other, and the measurement is 0.1162.
…
The reason for both failures is the same. The rule counts the shared positions and then treats each one as contributing its full weight, when in fact the sign of a shared position is a coin toss and the shared positions cancel each other. Once there are many of them the cancelling dominates, which is why the measurement falls further and further below the prediction as the directions fill.
Keep in mind
12. If they were exactly perpendicular, nothing would be lost
It is worth being precise about what near-perpendicularity is buying, because there is a clean statement available and it is stronger than the usual hand-wave. Suppose for a moment the drawn directions really were exactly at right angles to each other and all of the same length. Then multiplying the table of counts by them would be a rotation of the space the rows live in, and a rotation changes no angle between any two rows at all.
Every question anybody wanted to ask of the table would come back identical, and the narrowing would have cost nothing at all.
›Why this works
They are not exactly at right angles, and they cannot be, since a space of d numbers holds at most d directions mutually at right angles and there are usually more words than that. What Johnson and Lindenstrauss proved in 1984 is that this hardly matters. A random linear map into d dimensions keeps every distance among a set of points to within a factor of one plus or minus epsilon, provided d is roughly the logarithm of how many points there are divided by epsilon squared, and crucially that has nothing to do with how many dimensions the points started in.
Achlioptas showed in 2001 that a sparse map with entries only −1, 0 and +1 satisfies the same bound as one drawn from a bell curve.
The claim is checkable here rather than only citable, and the check produces a result I did not expect. At 2048 numbers a word, one draw happened to give all twenty-three words non-zero entries that never once landed in the same position, so the directions really were exactly at right angles, and every angle in the table came through the projection with a largest change of 3.8 × 10⁻¹⁷, which is the rounding of the arithmetic and nothing else.
At the same width, another draw left two pairs sharing a position, and the angles moved by 0.0109. Exactness is a property of the draw rather than of the width.
Keep in mind
13. Sparse and ternary is a choice about cost, and it turns out to be free
Nothing so far said the directions had to be mostly zeros. The original statements of this geometry drew every entry from a bell curve, and that works. The reason for four non-zero entries and nothing else is arithmetic in the inner loop. Adding a direction with four non-zero entries touches four numbers, and it touches four whatever the width is, so the reading of the collection does not get more expensive when the positions get wider.
A dense direction touches every position, so the same reading at 2048 numbers a word would cost five hundred times what it costs at four.
The entries being only −1, 0 and +1 removes the multiplication as well. Adding a direction becomes adding and subtracting ones at a handful of addresses, with no floating-point multiply anywhere in the reading.
The question that decides whether this is a compromise is what the sparsity costs in accuracy, and measured over twelve draws at each setting, it costs almost nothing.
| width | 2 non-zeros | 4 | 8 | 16 | 32 |
|---|---|---|---|---|---|
| 16 | 0.1770 | 0.1714 | 0.1729 | 0.1732 | does not fit |
| 64 | 0.0811 | 0.0670 | 0.0752 | 0.0832 | 0.0834 |
| 256 | 0.0364 | 0.0393 | 0.0378 | 0.0338 | 0.0357 |
How far the angles between two subject words moved away from the whole table’s answer, averaged over twelve draws. Across a row the numbers barely move; down a column they fall by roughly a factor of five.
Reading across a row, the widest and narrowest settings differ by 0.0056 at 16 numbers and by 0.0055 at 256, which is inside the swing one draw makes. Reading down a column, the same setting goes from 0.1714 to 0.0393 as the width grows. The width is doing all the work, so two non-zero entries can be chosen for the two slot updates they cost per neighbour rather than defended as a compromise.
Keep in mind
Part 4. What The Shortcut Costs
14. The neighbours are reordered rather than replaced
The honest way to price the shortcut is to build the table it avoids, ask it the same questions, and report the difference. Ask both which words are nearest to flour and the two answers hold the same words in a different order. Five of the fit’s six nearest are among the table’s six nearest, and the two disagree about which is first. The fit says eggs, which the table ranks third; the table says bake, which the fit ranks third.
That is the typical damage and it is mild. The sharper case is a pair the two readings disagree about in kind rather than in degree. Flour and anchor come out at 0.1208 in the table, a small positive number saying the two have a little in common through the words both halves share. In the fit they come out at −0.2437. Nothing about the collection made anchor the opposite of flour; the interference from a few directions that happened to share positions did.
Keep in mind
15. What each extra number a word buys
The measurement that prices the width is the same comparison applied to every pair of two subject words at once. Take all 190 of them, read the angle from the whole table, read it from the fit, and average how far apart the two answers are. At 8 numbers a word that gap is 0.3959, which is larger than most of the angles being compared. At 16 it is 0.1441, at 64 it is 0.0542, and at 2048 it is 0.0109.
…
Flour’s whole list of six nearest words is recovered at 64 numbers and not before, which is a more demanding test than the average gap and turns over at a definite place. Below that, at 8 numbers, only two of the six survive.
The line running across that picture is the count of pairs of drawn directions that still share a position, and the reason it is drawn beside the gap is that they fall together. At 16 numbers, 155 of the 253 pairs share one; at 2048, two pairs do, and the gap has fallen by a factor of thirteen.
In a model
16. Where a method that builds the table wins
There is a place where the shortcut is plainly worse than the alternative, and it is not about the projection at all. It is about what gets projected. The sum in Part 2 adds a neighbour’s direction once per occurrence, so a word that turns up beside everything contributes its direction to everything, and the positions of two words that share nothing but their function-word company are pulled together.
On the twenty-four documents the three words carrying no subject have the largest rows in the collection, 40 each against 35 for the largest subject word, and three rows out of twenty-three account for 16.7% of the whole table. A word carrying no subject comes out 0.5064 alike to a word that does, under the fit, where the whole table of raw counts says 0.5173 and a reading that first divides out what frequency alone would explain says 0.2207.
…
The fit inherits the raw table’s number almost exactly, which is what a faithful projection of the raw table should do. The method that builds the table has somewhere to put a repair and this one does not, because there is no moment at which the counts exist as counts to be reweighted. The usual answer is to discard the frequent words before reading, or to let a neighbour further away count less, and both are decisions taken before the reading rather than corrections applied after it.
Keep in mind
17. The work, counted honestly
It would be easy to leave the impression that the shortcut is always the cheap route. On this collection it is not, and the numbers say so.
| what is done | how much of it |
|---|---|
| word occurrences read | 144 |
| occasions one word is in another’s window | 720 |
| single numbers updated, one reading | 2,880 |
| cells the table of counts would hold | 529 |
| multiplications to project that table at 16 numbers | 8,464 |
| numbers in the answer | 368 |
The two routes to the same positions, on twenty-four documents of six words each with a window of five positions on either side.
Building the table needs 529 numbers to exist at once, and the answer needs 368, so the saving in memory is a factor of 1.44 and not worth the trouble. What decides it is how each figure grows. The 2,880 grows with how long the collection is and with how many non-zero entries a direction carries, and stops there. The 529 grows with the square of the vocabulary and the 8,464 grows with the square of the vocabulary times the width, and neither depends on how much or how little text there was.
In a model
Part 5. Where Random Indexing Stops Being Defined
18. Nearly perpendicular is not perpendicular, and more text does not help
Part 3 said the interference is exactly the pairs of directions that share a position. That has a consequence worth stating on its own, because it makes this error a different kind of thing from most of the errors on this site.
Which pairs share a position is settled by the draw, before any text is read. So the error it causes is not an error of estimation and does not shrink as the evidence accumulates. Write the same twenty-four documents out twice, and every count doubles; the positions all double with them; and an angle between two positions is unchanged by a common scale.
Measured, the gap against the whole table is 0.14412102749793634 with the collection written once, and at 0.14412102749793634 with it written eight times, and one pair of words comes out at 0.6270095706410385 in both, identical to the last bit.
Reading more text of course changes the counts, and better counts do give better answers. What does not change is the distortion the projection adds on top of whatever those counts say. That is a fixed function of the draw and the width, and the only two things that move it are drawing again and asking for more numbers.
Keep in mind
19. The width is chosen before anything is read
A method that builds the table and squeezes it has a diagnostic built into the squeeze. The directions come out ordered by how much of the table each accounts for, so a reader can look at where those figures fall away and cut there. The rule is a rough one, and it is at least a quantity the fit itself produced.
Here there is nothing of the kind. The width is fixed before the first word is read, every coordinate is as good as every other by construction, and the reading produces no figure that says whether the width was enough. Measured across the widths on this collection the gap falls from 0.3959 to 0.0109 without turning anywhere, so there is no elbow to find even if somebody went looking.
What can be done instead is to fit twice at different widths and see whether the answers agree, which is an external check rather than a reading of the fit. That is worth saying plainly, since it is the practical answer and it costs a second reading of the collection.
Keep in mind
20. The answer depends on the draw
Two fits of one collection at one width, differing in nothing but which positions the draw picked, are two different answers. How different is a measurable quantity and it is larger than it is comfortable to admit at the narrow end.
…
Over twenty draws at 8 numbers a word, one pair of cooking words comes back anywhere between 0.0189 and 0.9646, a spread of 0.9457 on a scale that runs from −1 to 1. The same pair over twenty draws at 16 numbers spreads by 0.4032, at 50 by 0.2853 and at 200 by 0.1182. Not one of those differences has anything to do with the collection.
The separation between the two halves holds up much better than any individual pair, which is worth knowing and is the reason the method is usable at all. At 16 numbers the smallest separation any of the twenty draws produced was 0.1735 and the largest 0.8430, and every one of them had the two halves the right way round.
Keep in mind
21. The cases with nothing to compute
Several inputs leave this method with nothing to work out rather than something approximate to work out, and a few more leave it with a genuine choice whose cost is worth knowing. The table gathers both, with what the mathematics says in each case.
| the case | what the method says |
|---|---|
| a word with no company at all | its position is a sum over nothing, which is the origin rather than a small number. The origin has no direction, so the angle between it and anything else is a zero divided by a zero and is undefined; a ranking of what such a word resembles does not exist rather than being empty. |
| two words whose company is identical | the same position exactly, whatever was drawn, since both sums are over the same collection of directions, and a sum is settled by what goes into it and by nothing else. That is correct rather than a failure, and it says the method can never tell such words apart, at any width and under any draw. |
| positions only two numbers wide | defined, and useless. With two non-zero entries in two positions only two directions exist at all, +1 then −1 and −1 then +1, so every word is handed one of two and every pair of positions comes out at exactly +1 or exactly −1. The measured answer for the whole collection is exactly those two values and nothing between them. |
| an odd number of non-zero entries | no draw satisfies it, since the construction asks for as many entries of +1 as of −1. There is a real choice attached, which is to allow the imbalance, and it costs the property that a direction sums to zero, so a long sum of directions would drift in one direction rather than staying centred. |
| more non-zero entries than there are positions | undefined. The positions are drawn without repeating, so asking for eight distinct slots in a direction four numbers long names a set that is not there. |
| how many numbers to give a word | a real choice with nothing inside the reading to settle it. Measured here, the gap against the whole table falls from 0.3959 at eight numbers to 0.0109 at two thousand and forty-eight, monotonically and without an elbow, so no quantity the fit produces turns over as the width passes a good value. |
| which draw was used | part of the answer rather than a detail of it. Two fits differing in nothing else gave one pair of words 0.0189 and 0.9646 at eight numbers a word, and spreads of 0.4032, 0.2853 and 0.1182 at sixteen, fifty and two hundred over twenty draws. |
| the value of a single coordinate | means nothing on its own and nothing across two draws. Position five of a word’s answer is the total of whichever words happened to be handed a non-zero entry in that slot, and a redraw hands them elsewhere. An angle between two words survives a redraw approximately; a coordinate does not survive it at all. |
| a pair of directions at exactly a right angle | that pair’s contribution is preserved exactly, and a draw in which no two directions share a position preserves every angle exactly. Measured at two thousand and forty-eight numbers, such a draw reproduced the whole table’s angles with a largest change of 3.8 × 10⁻¹⁷, and another draw at the same width, with two pairs sharing, moved them by 0.0109. |
| more text | changes the counts and does not touch the distortion. Which directions share a position is settled before any reading, and an angle is unmoved by a scale, so writing the collection out eight times leaves the gap at 0.14412102749793634 exactly as one copy did. |
| a word too rare to be given a position | a choice about the sentence it sat in rather than about the word. Dropping it makes the words on either side of it neighbours, which is what the published implementations do; leaving a gap instead makes the window’s reach depend on how many rare words happened to fall inside it. Neither is obviously right and the two give different counts. |
| which of two words stood first | outside what is represented. A position is a sum, and addition does not remember an order, so a sentence and its reverse produce the same positions for every word in it. |
| which sense of a word is meant | outside what is represented. One direction per spelling, so a word used for two unrelated things adds both sets of company into one position and settles between them, and there is no second position for the second sense to occupy. |
Keep in mind
Check yourself
Questions on Parts 3 to 5
Question 1 of 5
At eight positions the rule n over d predicts an overlap of 0.5000 and the measurement is 0.2994. What is the rule missing?
Try it with Botie
Build with Botie
Write and run Python