Math 水库抽样中随机数的再利用

Math 水库抽样中随机数的再利用,math,random,probability,reservoir-sampling,Math,Random,Probability,Reservoir Sampling,最近有人就另一个问题询问: 我知道你不应该这么做,我只是不能用我的手指去解释为什么不 请看示例代码: 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

最近有人就另一个问题询问:

我知道你不应该这么做,我只是不能用我的手指去解释为什么不

请看示例代码:

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]

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

编辑,回应评论:

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

但是,使用
fixed()
,选择决定和上一个箱子号都取决于相同的固定32位数字。这意味着从每个箱子中取出样品的可能性将不一致


考虑在
sample()
循环的第三次迭代期间发生的情况。您有三个现有的存储箱(0、1和2),您希望在每个存储箱中拾取1/4的样本,并将它们添加到新创建的存储箱3中

请注意,存储单元1中的所有32位
fixed()
数字都将是偶数(因为第一次通过选择了可被2整除的所有数字),而存储单元0中的所有数字都将是奇数(因为偶数数字已移动到存储单元1)。第二步将所有可被3整除的数字移动到存储单元2(到目前为止,这应该是正常的,并且不会改变存储单元0和1中的偶数/奇数除法)

第三遍将所有可被4整除的
fixed()。但是,这将选择Bin1中一半的数字(因为所有偶数中有一半可被4整除),而Bin0中没有一个数字(因为它们都是奇数)。因此,即使新料仓的预期大小应该正确,旧料仓的预期大小也不再相同

这就是
fixed()
产生不均匀分布的原因:如果该数字以可预测的方式依赖于用于选择原始存储箱的数字,则违反了隐式假设,即您可以通过选择一个随机数来选择每个存储箱的精确部分


随机数的基本特性是,在统计意义上,每个样本必须独立于前面的样本分布。基于随机数的算法依赖于此特性

伪随机数生成器(PRNG)实际上不是随机的;正如你所知,他们的结果实际上是一个固定的序列。PRNG结果被故意置乱,以便在大多数情况下,它们的行为足够像实际的随机数。但是,如果PRNG对特定应用程序而言“较弱”,则PRNG的内部工作可以以奇怪的方式与应用程序的细节交互,从而产生非常非随机的结果

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


尽管
fixed()
是一个故意破坏的PRNG,但许多商业库PRNG“很弱”,最终可能与某些应用程序发生类似的奇怪交互。实际上,“弱点”是与应用程序相关的——虽然有一些统计测试被广泛用于暴露弱PRNG,但不能保证应用程序不会偶然发现偶数个“强”的奇怪相关性PRNG.

思考一下:当您的固定数字非常小时会发生什么情况?

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

那么,每个流一个随机数的问题是什么?为什么它会扭曲分布

我还没有找到一个完整的答案,但我有一个想法

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

它什么时候赢?首先,它必须是N%2==0。所以它必须是一个偶数。此外,它也会被流中2的每一个倍数、4…6…8…10等的每一个倍数击败,但它会赢,例如106

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

现在让我们取4,它需要是N%4==0,并且它被4到N(8…12…16)的所有倍数所击败。如果我们计算4能赢多少次,我们得到45次。。。!所以分配是不公平的

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

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

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


不是(1/2+1/3+1/4+1/5+1/6(…等))

您确定在这里使用的是相同的随机数吗?看起来你每次都在初始化一个不同的修复…@TimGee是的,这是有意的;每次调用sample时使用新的fixed()时,随机数不是