Reservoir Sampling
A way to pick a uniformly random sample from a stream of unknown length, using a fixed amount of memory, without ever storing the whole stream.
Prerequisites: Pseudorandom Number Generators
Suppose a tick feed is firing prices at you all day and, at market close, you want a single tick chosen uniformly at random from everything that arrived — but you don't know in advance how many ticks there will be, and you can't afford to store all of them just to pick one later. Reservoir sampling solves exactly this: pick a random sample from a stream of unknown, possibly huge, length, using memory proportional only to the sample size.
Keep the first items outright. For every item after that, at position , replace a random slot in your kept set with probability . When the stream ends, every item that ever arrived had exactly the same chance of being in the final sample — no matter how long the stream ran.
The one-item case
Start with . Keep the first item as your current pick. When the second item arrives, replace your pick with it with probability — a coin flip. When the third item arrives, replace with probability . In general, when item arrives, replace with probability .
Why does this end up uniform? By induction: assume after items, each has probability of being the current pick. Item becomes the pick with probability — correct for it. An already-picked item survives only if not replaced, probability , so its chance after this step is — still uniform. The algorithm never needs to know how many items are left to come.
Worked example
A stream delivers ticks in order, and we sample .
- arrives: pick .
- arrives (item 2): replace with probability . Say the coin says yes: pick .
- arrives (item 3): replace with probability . Say no: pick stays .
- arrives (item 4): replace with probability . Say no: pick stays .
Run this process many times over the same stream and count how often each letter ends up chosen — it converges to 25% each, exactly uniform, even though "survived" two rejection rounds it happened to win.
Drag the parameters above and watch how a binomial with mirrors the chance any single stream position ends up as the kept sample — the mechanism behind why the replace-with-probability- rule produces a flat, uniform outcome across positions.
Extending to k items
For a sample of size , keep the first items as the initial reservoir. For each subsequent item , generate a random integer between 1 and . If , overwrite reservoir slot with the new item; otherwise discard it. The same inductive argument holds slot by slot, and the whole scan costs time and only memory — you never allocate space for the full stream.
What this means in practice
Reservoir sampling shows up whenever a quant needs a random subset from something too large or too live to store: sampling log lines from a production trading system for a monitoring dashboard, drawing a random validation subset from a data pipeline that streams rows rather than loading a full table, or picking a random backtest window from years of tick data without holding it all in RAM. It is also a favorite coding-interview question precisely because the "obvious" answer — store everything, then sample — fails the moment the interviewer says "the stream doesn't fit in memory."
The classic mistake is using instead of as the replacement probability for later items, or applying a constant replacement probability throughout. The probability of replacement must shrink as grows, or later items get admitted too easily and the sample stops being uniform over the whole stream.
Related concepts
Practice in interviews
Further reading
- Vitter, 'Random Sampling with a Reservoir' (ACM TOMS, 1985)
- Cormen et al., Introduction to Algorithms (streaming algorithms discussion)