蓄水池抽样问题

本文介绍了一种在数据流中进行随机抽样的方法——蓄水库抽样算法。该算法适用于数据量庞大且无法预知总数的情况,如搜索引擎关键字的随机抽取。通过保持一个固定大小的蓄水库,并以特定概率更新其中的元素,确保每个元素被抽中的机会均等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

部分内容转自http://handspeaker.iteye.com/blog/1167092

http://blog.youkuaiyun.com/hackbuteer1/article/details/7971328


这种应用的场景一般是数据流的情况下,由于数据只能被读取一次,而且数据量很大,并不能全部保存,因此数据量N是无法在抽样开始时确定的;但又要保持随机性,于是有了这个问题。所以搜索网站有时候会问这样的问题。


此类型的算法题有:谷歌面试题:给定一个数据流,其中包含无穷尽的搜索关键字(比如,人们在谷歌搜索时不断输入的关键字) 。如何才能从这个无穷尽的流中随机的选取 1000 个关键字?


这里的核心问题就是“随机”,怎么才能是随机的抽取元素呢?我们设想,买彩票的时候,由于所有彩票的中奖概率都是一样的,所以我们才是“随机的”买彩票。那么要使抽取数据也随机,必须使每一个数据被抽样出来的概率都一样。


【解决】
解决方案就是蓄水库抽样(reservoid sampling)。主要思想就是保持一个集合(这个集合中的每个数字出现),作为蓄水池,依次遍历所有数据的时候以一定概率替换这个蓄水池中的数字。
其伪代码如下:

 

                       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

 

证明:每次选择时,蓄水池出现每个数的概率为k/(已选过的数字数目)。用归纳法证明:

1.当 i <= k 时,第i个数出现在蓄水池中的概率为1.
2.假设当选到第i个数时,前i个数出现在蓄水池中的概率为k/i

3.当i+1个数时,第i+1个数出现在蓄水池中的概率为这个数被选中替换蓄水池中的数的概率,也就是k/i+1;

前i个数出现在蓄水池中的概率为,前i次替换中出现在蓄水池中(事件A)且第i+1次没有被替换的概率(事件B).p = P(A)*P(B);

P(A) = k/i,根据假设;P(B) = P(第i+1个数没被选中)+P(第i+1个数被选中)*P(当前数字不是被替换的数字)= (1- k/(i+1)) + k/(i+1) * (k-1)/k = i/(i+1);

所以p = k/i * i/(i+1) = k/(i+1)

故证明成立 


同样的道理可以应用到类似的题目中,例如:

谷歌面试题:给定一个未知长度的整数流,如何随机选取一个数

方法:保存一个数作为蓄水池,对第i个数,用1/i的概率替换蓄水池中的那个数,最后得到随机数。利用这种方法,我们只需保存一个随机数,和迄今整数流的长度即可。所以可以处理任意长的整数流。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值