Live data from Hacker News

Vitter's reservoir sampling algorithm D: randomly selecting unique items

getkerf.wordpress.com

31–40 of 83 posts

Re: Vitter's reservoir sampling algorithm D: randomly selecting unique items

#31

Why cannot you just create random numbers and discard duplicates? For practical purposes when list.length << total.lenght shouldn't that be good enough?

I think the other replies to you are mistaken. This algorithm meets the requirements of running in linear time, once you apply the inverting trick when the sample size exceeds half of the pool size. See my top-level comment.

Re: Vitter's reservoir sampling algorithm D: randomly selecting unique items

#32

This may be a stupid question, but what exactly is wrong with (using the dealing random cards analogy): for i = 1 to k pickedCardIndex = randomInt(n - i) hand[i - 1] = deck[pickedCardIndex] swap(deck[pickedCardIndex], deck[n - i]) As far as I can see this satisfies all conditions stated by the author (assuming that randomInt(x) produces a uniformly random integer in the range [0, x], there are n cards in the deck arr…

I think you aren't allowed to mutate the deck.

Re: Vitter's reservoir sampling algorithm D: randomly selecting unique items

#33
post #7

> Reservoir sampling is a family of randomized algorithms for randomly choosing a sample of k items from a list S containing n items, where n is either a very large or unknown number. Typically n is large enough that the list doesn't fit into main memory. So if N is really large and doesn't fit into main memory, how does one iterate over such large list in a reasonable amount of time? When I am taught algorithm my sa…

The algorithm accesses each element in the input only once, and in order.

It's like reading a big file. Just call read() repeatedly, and discard old data each time you call read() again.

Re: Vitter's reservoir sampling algorithm D: randomly selecting unique items

#34

Why cannot you just create random numbers and discard duplicates? For practical purposes when list.length << total.lenght shouldn't that be good enough?

In certain circumstances, like when you're drawing from a limited pool, this becomes N^2 and unbounded - Imagine you're trying to shuffle a deck of cards. Select a card number, 1-52. The first draw, you're guaranteed to get a unique card, the second, you've got a 1/52 chance of having to generate a second number, all the way up to the final card you have a 1/52 chance of generating the final number you need, and you'…

"The nicer way to do this is to have two lists. Put all of your cards into the first list. Choose a number between 1 and the length of list 1, then remove that element from the list and add it to the end of list 2. Repeat until list 1 is empty. It's linear-time (with a linked list), and there's no chance of duplicates."

I have to add my $0.02. This is correct, your algorithm will give correct result with no chance of duplicates. However in some context this absolutely must not be done - I've worked in a company which made online gambling games and the auditing requirement was 1-to-1 correspondence of number drawn from RNG and the card player sees. For example Ace of spades must always be 49, whether it was drawn as first or last card from the deck.

Re: Vitter's reservoir sampling algorithm D: randomly selecting unique items

#35
post #22

Here is an alternative: Use a multiplicative linear congruential generator with a period 2^n , where n is ceil(log2(m)), where m is the size of the list. Seed the generator, start generating values and drop all values that are larger than m. In the worst case you will have to drop half of the values, in the best case you will drop none. This depends on how close to a power of 2 m is. The generator is very short, one…

The generator is also highly predictable and suffers from defects that may affect the overall analysis.

Re: Vitter's reservoir sampling algorithm D: randomly selecting unique items

#37
post #22

Here is an alternative: Use a multiplicative linear congruential generator with a period 2^n , where n is ceil(log2(m)), where m is the size of the list. Seed the generator, start generating values and drop all values that are larger than m. In the worst case you will have to drop half of the values, in the best case you will drop none. This depends on how close to a power of 2 m is. The generator is very short, one…

This works, and is so much simpler.

It's not quite the same problem though; the algorithm described returns samples in sequential order. They mention performance reasons for this (C-f "tape sampling"). It also has the limitation that you need to know the sample size in advance.

Re: Vitter's reservoir sampling algorithm D: randomly selecting unique items

#38
post #35
post #22

Here is an alternative: Use a multiplicative linear congruential generator with a period 2^n , where n is ceil(log2(m)), where m is the size of the list. Seed the generator, start generating values and drop all values that are larger than m. In the worst case you will have to drop half of the values, in the best case you will drop none. This depends on how close to a power of 2 m is. The generator is very short, one…

The generator is also highly predictable and suffers from defects that may affect the overall analysis.

This only matters in calculations where randomness is important, i.e. Monte Carlo method.

Nevertheless, if you don't use the least significant bits, and if the constants are carefully chosen, MLCG passes most of the hardest statistical tests. For example it passes all DIEHARD tests, and most of TESTU01.

Re: Vitter's reservoir sampling algorithm D: randomly selecting unique items

#39
GNU coreutils' shuf since v8.22 (Dec 2013) implements this to minimize memory usage when sampling large files or unknown numbers of items read from a pipe.

For example this command never finishes, but consumes a constant (small) amount of mem.

  seq inf | shuf -n1

Re: Vitter's reservoir sampling algorithm D: randomly selecting unique items

#40

The C code in this article is a mirror of the code from Appendix 2 in Vitter's paper, which I guess explains/excuses the abbreviated variable names. The paper says things like, "use an exponentially distributed random variate Y," and uses variable names like n, N, U, S, X, y1, and y2 in the appendix. Nonetheless, I find this coding style unreadable. "Y" is not a very good name for an exponentially distributed random…

On the other hand, you need the original names in order to reference back to the paper.

random_variate_y

:P

Post reply on HN