在水库采样中重新使用随机数

时间:2012-01-02 16:42:31

标签: math random probability

最近有人询问了另一个问题:Given an unknown length list, return a random item in it by scanning it only 1 time

我知道你不应该,我只是不能指责为什么不这样做。

查看示例代码:

import random, sys

def rnd(): # a function that returns a random number each call
    return int(random.getrandbits(32))

class fixed: # a functor that returns the same random number each call
    def __init__(self):
        self._ret = rnd()
    def __call__(self):
        return self._ret

def sample(rnd,seq_size):
    choice = 0
    for item in xrange(1,seq_size):
        if (rnd() % (item+1)) == 0:
            choice = item
    return choice

dist = [0 for i in xrange(500)]
for i in xrange(1000):
    dist[sample(rnd,len(dist))] += 1
print "real",dist
print

dist = [0 for i in xrange(500)]
for i in xrange(1000):
    dist[sample(fixed(),len(dist))] += 1
print "reuse",dist

为每个项目生成一个新的随机数的适当油藏采样的选择应该很好地均匀分布:

real [1, 3, 0, 1, 2, 3, 2, 3, 1, 2, 2, 2, 2, 0, 0, 1, 3, 3, 4, 0, 2, 1, 2, 1, 1, 4, 0, 3, 1, 1, 2, 0, 0, 0, 1, 4, 6, 2, 3, 1, 1, 3, 2, 1, 3, 3, 1, 4, 1, 1, 2, 2, 5, 1, 2, 1, 0, 3, 1, 0, 2, 6, 1, 2, 2, 1, 1, 1, 1, 3, 2, 1, 5, 4, 0, 3, 3, 4, 0, 0, 2, 1, 3, 2, 3, 0, 2, 4, 6, 3, 0, 1, 3, 0, 2, 2, 4, 3, 2, 1, 2, 1, 2, 2, 1, 4, 2, 0, 0, 1, 1, 0, 1, 4, 2, 2, 2, 1, 0, 3, 1, 2, 1, 0, 2, 2, 1, 5, 1, 5, 3, 3, 1, 0, 2, 2, 0, 3, 2, 3, 0, 1, 1, 3, 0, 1, 2, 2, 0, 1, 2, 2, 3, 2, 3, 1, 1, 0, 1, 2, 2, 2, 2, 2, 3, 2, 1, 2, 2, 2, 1, 3, 3, 1, 0, 1, 1, 0, 1, 3, 2, 1, 4, 3, 4, 1, 1, 1, 2, 1, 2, 0, 0, 0, 1, 1, 2, 6, 0, 1, 1, 0, 1, 0, 1, 2, 2, 3, 0, 1, 2, 2, 1, 0, 4, 2, 1, 2, 2, 0, 4, 4, 0, 3, 2, 2, 1, 2, 4, 1, 2, 1, 0, 2, 1, 1, 5, 1, 2, 2, 3, 2, 3, 0, 1, 2, 3, 2, 5, 2, 3, 0, 1, 1, 1, 1, 3, 4, 2, 4, 1, 2, 3, 2, 5, 2, 1, 0, 1, 1, 2, 2, 3, 1, 1, 1, 2, 1, 2, 0, 4, 1, 1, 2, 3, 4, 3, 1, 2, 3, 3, 3, 2, 1, 2, 0, 0, 4, 3, 2, 2, 5, 5, 3, 3, 3, 1, 0, 1, 3, 1, 1, 2, 4, 3, 1, 4, 4, 2, 5, 0, 5, 4, 2, 1, 0, 4, 1, 3, 3, 2, 4, 2, 3, 3, 1, 3, 3, 4, 2, 2, 1, 1, 1, 1, 3, 3, 5, 3, 2, 4, 0, 1, 3, 2, 2, 4, 2, 2, 3, 4, 5, 3, 2, 1, 2, 3, 2, 2, 2, 4, 4, 0, 1, 3, 3, 3, 4, 1, 2, 4, 0, 4, 0, 3, 2, 1, 1, 4, 2, 1, 0, 0, 0, 4, 2, 2, 1, 4, 3, 1, 1, 3, 2, 4, 3, 4, 2, 1, 1, 2, 2, 3, 3, 1, 2, 2, 1, 1, 2, 3, 1, 9, 1, 3, 4, 2, 4, 4, 0, 1, 0, 1, 0, 2, 1, 0, 1, 2, 3, 3, 6, 2, 2, 1, 2, 4, 3, 3, 3, 2, 1, 2, 1, 2, 8, 2, 3, 1, 5, 3, 0, 2, 1, 1, 4, 2, 2, 1, 2, 3, 2, 1, 0, 4, 3, 4, 3, 1, 3, 2, 3, 2, 2, 1, 0, 1, 2, 5, 3, 0, 3, 1, 2, 2, 2, 1, 0, 1, 4]

然而,当您为所有项目重复使用相同的随机数时,您会得到一个偏向极低数字的分布:

reuse [92, 50, 34, 19, 23, 16, 13, 9, 9, 9, 11, 10, 6, 7, 8, 5, 5, 6, 4, 2, 2, 3, 2, 3, 3, 6, 6, 1, 4, 3, 5, 2, 2, 1, 1, 2, 3, 4, 3, 4, 1, 3, 1, 0, 0, 1, 5, 3, 1, 2, 0, 2, 0, 1, 1, 6, 2, 0, 2, 2, 4, 2, 2, 0, 2, 2, 2, 0, 3, 0, 4, 1, 2, 1, 4, 2, 2, 0, 1, 0, 1, 1, 0, 0, 0, 2, 0, 0, 2, 0, 0, 1, 0, 0, 1, 0, 2, 0, 0, 1, 2, 1, 3, 1, 0, 1, 2, 0, 4, 3, 0, 0, 2, 0, 0, 1, 0, 0, 2, 0, 2, 1, 0, 1, 0, 0, 1, 1, 3, 0, 1, 1, 0, 2, 0, 1, 2, 0, 1, 1, 4, 1, 1, 1, 2, 1, 0, 1, 2, 0, 2, 1, 1, 2, 0, 1, 1, 0, 2, 0, 2, 0, 0, 2, 0, 1, 0, 2, 1, 1, 0, 0, 1, 2, 4, 1, 0, 2, 0, 1, 2, 1, 3, 0, 1, 0, 0, 1, 0, 0, 2, 1, 0, 0, 0, 3, 2, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 4, 1, 0, 2, 1, 0, 0, 2, 1, 1, 3, 3, 2, 0, 1, 0, 2, 0, 1, 1, 0, 0, 3, 1, 0, 0, 1, 0, 3, 2, 2, 0, 0, 0, 0, 0, 2, 0, 1, 0, 2, 0, 4, 1, 0, 0, 2, 0, 1, 1, 0, 0, 3, 1, 3, 2, 2, 1, 3, 1, 2, 0, 1, 1, 3, 0, 3, 1, 2, 0, 2, 0, 2, 0, 3, 0, 3, 0, 3, 1, 0, 2, 3, 1, 1, 0, 1, 3, 3, 1, 1, 1, 0, 2, 1, 1, 4, 1, 1, 1, 2, 0, 3, 1, 1, 0, 4, 1, 1, 0, 1, 3, 1, 0, 1, 1, 0, 3, 3, 0, 2, 4, 0, 1, 2, 1, 6, 1, 0, 0, 0, 0, 1, 2, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 4, 2, 0, 1, 2, 0, 1, 4, 1, 2, 0, 5, 2, 2, 0, 6, 2, 2, 1, 3, 0, 3, 1, 1, 0, 3, 1, 4, 2, 0, 1, 0, 1, 2, 3, 1, 1, 3, 0, 0, 0, 1, 1, 4, 3, 3, 0, 0, 1, 0, 1, 1, 2, 1, 0, 2, 1, 4, 5, 1, 1, 3, 0, 1, 1, 1, 3, 1, 1, 0, 3, 3, 1, 3, 0, 1, 0, 0, 1, 1, 3, 2, 1, 0, 3, 1, 1, 3, 1, 3, 1, 2, 2, 2, 0, 0, 5, 1, 3, 0, 1, 4, 1, 1, 1, 3, 2, 1, 3, 2, 1, 3, 1, 2, 2, 3, 2, 2, 1, 0, 3, 3, 1, 3, 3, 3, 2, 1, 2, 3, 3, 3, 1, 2, 2, 2, 4, 2, 1, 5, 2, 2, 0]

这里的数学是什么?为什么你不能重复使用相同的随机数?

3 个答案:

答案 0 :(得分:7)

编辑,回应评论:

水库采样应该工作的方式是:您希望从每个现有垃圾箱中精确选择正确比例的样本,以便以相同的概率组成一个额外的垃圾箱。在sample()循环中,假设您随机抽取了一个item个分箱,则需要从每个分箱中选择样本,概率为1/(item + 1)

但是,对于fixed(),选择决策和前一个bin编号都取决于相同的固定32位数。这意味着从每个箱中取出样品的可能性不均匀。


考虑在sample()循环的第三次迭代期间发生了什么。您有三个现有的箱(0,1和2),并且您想要在每个箱中挑选1/4的样本并将它们添加到新创建的箱3中。

请注意,bin 1中的所有32位fixed()数字都是偶数(因为第一遍选中了所有可被2整除的数字),而bin 0中的所有数字都是奇数(因为偶数被转移到bin 1)。第二遍将所有可被3整除的数字移动到bin 2(到目前为止应该没问题,并且不会改变二进制0和1中的偶数/奇数除法。)

然后第三遍将所有fixed()个可被4整除的数字移动到bin 3中。但是,这将从bin 1中选择一半的数字(因为所有偶数的一半可以被4整除),并且没有来自bin 0的数字(因为它们都是奇数)。因此,即使新垃圾箱的预期尺寸应该是正确的,旧垃圾箱的预期尺寸也不再相同。

这就是fixed()生成不均匀分布的方式:如果该数字以可预测的方式取决于所使用的数字,则违反了通过选择随机数可以选择每个分箱的精确分数的隐含假设选择原来的垃圾箱。


随机数的基本属性是每个样本必须从统计意义上的前一个样本中独立分布。基于随机数的算法取决于此属性。

伪随机数生成器(PRNG)实际上并不是随机的;如你所知,他们的结果实际上是一个固定的序列。 PRNG结果是故意加扰的,因此它们就像大多数用途的实际随机数一样。但是,如果PRNG对于特定应用程序来说“弱”,则PRNG的内部工作方式可以以奇怪的方式与应用程序的详细信息交互,以非常随机的结果。

通过重新使用相同的随机数,你在这里尝试的是建立一个糟糕的PRNG。实际结果取决于应用程序如何使用随机数...

的详细信息

尽管fixed()是一个故意破坏的PRNG,但许多商业库PRNG都是“弱”的,并且最终可能会与某些应用程序发生类似的奇怪交互。实际上,“弱点”与应用程序相关 - 虽然有一些统计测试被广泛用于尝试揭示弱PRNG,但无法保证您的应用程序不会偶然发现甚至一些奇怪的相关性一个“强大的”PRNG。

答案 1 :(得分:1)

如果您每次都选择一个随机数,则流中的下一个项目有1 / CURRENTSIZE的机会击败上一个选中的项目。

那么一个随机数每个流会出现什么问题?为什么会扭曲分布?

我还没有找到完整的答案,但我有个主意。

例如,让我们取一个100个数字的流,然后选择一个随机数0 ... 999。现在我们从第二个项目的角度来看待它。

什么时候赢了?好吧,首先,它需要是N%2 == 0。所以它必须是偶数。此外,它也被流中的每个倍数2的每个其他倍数击败,4 ... 6 ... 8 ....等等。但它例如在106上获胜。

计算它赢得的所有数字,0..999,我们得到81次!

现在让我们取4,它需要是N%4 == 0并且它被4到N(8 ... 12 ...... 16)的所有倍数击败。如果我们计算4次获胜的次数,我们会得到45次......!因此分配不公平。

如果您将随机数最大化为流的大小,则可以修复此问题,然后所有人都有1次获胜机会,使其再次成为均匀分布。

例如,如果我们的流大小为100,我们选择0..199的随机数。我们知道前100个随机数都有一个匹配,所以它们是均匀分布的。但随机数99 ... 199会发生什么?分布不均匀!例如,101只给出101%X == 0表示1.对于所有素数(101,103,107,109,113,127,131,137,139,149,151,157,163, 167,173,179,181,191,193,197,199)。因此,第一项比其他项目获胜的机会更大。

如果您为每个项目选择一个新的随机数,则不是这种情况,在这种情况下可以添加机会。例如,当第一项出现时,它有获胜的机会:

NOT(1/2 + 1/3 + 1/4 + 1/5 + 1/6(......等))

答案 2 :(得分:0)

想一想:当您的固定电话号码真的很小时会发生什么?