Knuth用于水库采样的伪代码中可能存在的错误

时间:2013-07-14 11:26:06

标签: algorithm random combinations

以下是Knuth for Reservoir Sampling的pseodo代码(如何从一组k数字中选择n个数字,确保每个数字具有相同的概率)。

Init:一个大小为k的水库。

for i = k+1 to N
    M = random(1, i);

    if (M < k) // should this be if (M <= k)
       SWAP the Mth value and ith value
    end if    
end for

从此代码中,M < K的概率为(k-1)/i,而非k/i,因此我认为循环体中的if语句应为{{1} }}。我试着测试它们之间的区别,但我没有到达任何地方。

2 个答案:

答案 0 :(得分:4)

你是对的。但是,你的代码没有正确实现算法R.这个bug是你的(或者是谁编写了这段代码),而不是Knuth的; - )

引自Knuth(计算机程序设计艺术Vol.2 3Ed 1998,p.144):

  

...如果我们事先不知道N的值,就会出现问题,因为N的精确值在算法S中是至关重要的。假设我们想要从文件中随机选择n个项目,而不确切地知道该文件中有多少个。我们可以先查看记录,然后再通过第二遍来选择它们;但通常更好的是采样m>第一遍中的原始项目中的n个,其中m远小于N,因此在第二遍中必须考虑m个项目。当然,诀窍就是这样做   这样一种方式,即最终结果是原始文件的真正随机样本。

     

由于我们不知道输入何时结束,我们必须跟踪到目前为止看到的输入记录的随机样本,因此总是为最终做好准备。当我们阅读输入时,我们将构建一个“库”,其中仅包含先前样本中出现的记录。前n个记录总是进入水库。当输入(t + 1)st记录时,对于t> n,我们将在内存中有一个n个索引的表,指向我们从第一个t中选择的记录。问题是保持这种情况,增加1,即从现在已知的t + 1记录中找到一个新的随机样本。不难看出我们应该以新概率n /(t + 1)在新样本中包含新记录,在这种情况下,它应该替换前一个样本的随机元素。

     

因此,以下程序完成了这项工作:

     

算法R (水库采样)。从未知大小的文件中随机选择n个记录&gt; n,给定n> 0.称为“库”的辅助文件包含最终样本的候选记录。该算法使用不同索引 I [j]的表来表示1&lt; j&lt; n,每个都指向水库中的一个记录。

     

R1。 [初始化。]输入前n个记录并将它们复制到储存库。设置 I [j]←j为1&lt; j&lt; n,并设置t←m←n。 (如果正在采样的文件少于n个记录,则当然有必要中止算法并报告失败。在此算法期间,索引 I [1],..., [n]指向当前样本中的记录; m是库的大小; t是到目前为止处理的输入记录数。)

     

R2。 [文件结束?]如果没有更多要输入的记录,请转到步骤R6。

     

R3。 [生成并测试。]将t增加1,然后生成1到t(含)之间的随机整数M.如果M> n,转到R5。

     

R4。 [添加到水库。]将输入文件的下一条记录复制到水库,将m增加1,然后设置I [M]←m。 (I [M]先前指出的记录在样本中被新记录替换。)返回R2。

     

R5。 [跳过。]跳过输入文件的下一条记录(不要将其包含在水库中),然后返回步骤R2。

     

R6。 [第二遍。]对 I 表条目进行排序,以便 I [1]&lt; ......&lt; I 的[N];然后通过水库,将带有这些指数的记录复制到保存最终样本的输出文件中。

算法R的伪代码看起来像:

for j= 1 to n
    Reservoir[j]= File.GetNext()
    I[j]= j

t=n // number of input records so far
m=n // size of the reservoir

while not File.EOF()
    x= File.GetNext()
    t++
    M= Random(1..t)
    if (M<=n)
        m++
        Reservoir[m]= x
        I[M]= m

Sort(I[1..n])

for j= 1 to n
    Output[j]= Reservoir[I[j]]

答案 1 :(得分:3)

是的,它应该是<=。这是基于查看wikipedia中的代码,并通过this answer,这是一个很好的解释,为什么超集中的每个数字都有相同的出现机会。但是,我会毫不犹豫地声称Knuth有一个错误!