首页 > 其他 > 详细

蓄水池抽样(Reservoir Sampling)

时间:2016-03-07 01:21:40      阅读:300      评论:0      收藏:0      [点我收藏+]

  How could you select one of n objects at random, where you see the objects sequentially but you do not know the value of n beforehand? For concreteness, how would you read a text file, and select and print one random line, when you don’t know the number of lines in advance?

  问题定义可以简化如下:在不知道文件总行数的情况下,如何从文件中随机的抽取一行?

  首先想到的是我们做过类似的题目吗?当然,在知道文件行数的情况下,我们可以很容易的用C运行库的rand函数随机的获得一个行数,从而随机的取出一行,但是,当前的情况是不知道行数,这样如何求呢?我们需要一个概念来帮助我们做出猜想,来使得对每一行取出的概率相等,也即随机。这个概念即蓄水池抽样(Reservoir Sampling)

  有了这个概念,我们便有了这样一个解决方案:定义取出的行号为choice,第一次直接以第一行作为取出行 choice ,而后第二次以二分之一概率决定是否用第二行替换 choice ,第三次以三分之一的概率决定是否以第三行替换 choice ……,以此类推,可用伪代码描述如下:

i = 0

while more input lines

           with probability 1.0/++i

                   choice = this input line

print choice

  这种方法的巧妙之处在于成功的构造出了一种方式使得最后可以证明对每一行的取出概率都为1/n(其中n为当前扫描到的文件行数),换句话说对每一行取出的概率均相等,也即完成了随机的选取。

  证明如下:

技术分享

  回顾这个问题,我们可以对其进行扩展,即如何从未知或者很大样本空间随机地取k个数?

  类比下即可得到答案,即先把前k个数放入蓄水池,对第k+1,我们以k/(k+1)概率决定是否要把它换入蓄水池,换入时随机的选取一个作为替换项,这样一直做下去,对于任意的样本空间n,对每个数的选取概率都为k/n。也就是说对每个数选取概率相等。

  伪代码:

Init : a reservoir with the size: k

for i= k+1 to N

    M=random(1, i);

    if( M < k)

     SWAP the Mth value and ith value

end for   

//stream代表数据流  
//reservoir代表返回长度为k的池塘  
  
//从stream中取前k个放入reservoir;  
for ( int i = 1; i < k; i++)  
    reservoir[i] = stream[i];  
for (i = k; stream != null; i++) {  
    p = random(0, i);  
    if (p < k) reservoir[p] = stream[i];  
return reservoir;  

  证明如下:

  技术分享

 

蓄水池抽样(Reservoir Sampling)

原文:http://www.cnblogs.com/ducong/p/5249107.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!