蓄水池问题(等概率抽取)详解

来源:互联网 发布:jsp项目源码 编辑:程序博客网 时间:2024/06/16 07:22

蓄水池问题

问题背景:如何在N个数据中 等概率地取出k个。如果N会随着时间增长呢?

  1. 我们先来考虑简单的,就是如何在数据总数会增长的情况下等概率取出其中一个。
    设想一段流水线不断流来产品,要求随机取出一个。第一个,很简单,直接取得即可
    概率为1/1。如果第二个到来,那么我们在0.5和1直接取得一个随机数,如果大于0.5那么用第二个替换掉第一个,否则不替换。这样前两个每个被选中的概率都是1/2。
    第三个来了,我们以1/3的概率选中第三个,如果选中了,则用它替换掉前面已经选中的
    这样前三个每个被选中的概率都是1/3。

    简单证明:很显然3被选中概率是1/3, 对于2,在前两轮中被选中概率是1/2,第三轮中不被替换的概率
    (即3不被选中的概率)是2/3,所以p(选中2) = 1/2 * 2/3 = 1/3, 同理1被选中的概率也是1/3。
    推广:对于总数为N的流水线等概率选择一个,令i = 2开始,以p = 1/i的概率选中当前数,来替换掉已经选中的
    数,这样可保证前i个数每个被选中的概率都等于1/i。
    数学归纳法:
    i=2,成立。
    假设i=j成立,则只需证明i=j+1也成立即可。
    i = j+1 时,取random(1,j+1),在i到j+1之间取一个随机数,如果等于1,那么用第j+1个数替换掉选中的数。
    由于p(随机数=1)=1/j+1, 所以第j+1个数被选中概率为1/j+1。对于前j个数,他们被选中概率为1/j,在这种情况下不被替换的概率是
    j/j+1,所以综合来看被选中概率为1/j * j/j+1 = j/j+1, 可见i= j+1 也成立,得证。

  2. 继续推广,在N个数中等概率选k个呢?假设第i个数为a[i] 根据1中结论,直接给出伪代码:
    for i = k+1 to N:
    n = random(1,i);
    if(n <= k) 用a[i]随机替换掉已经选定的k个数中的一个;
    endfor;

    *解释:从第i=k+1个数开始,用p = k / i的概率选定a[i],如果选定,则等概率替换掉选定的k个数中的一个。
    这样可以做到前i个数每个被选到的概率都是k/i+1;
    归纳法证明:
    * 初始: i = k+1时,a[i]被选定概率为k/k+1,前k个数每个被选定概率为1-1/k * k/k+1=k/k+1(即
    减去被替换掉的概率),可见对前k+1个数选定概率都为k/k+1,即可i=k+1成立;
    * 假设当i = j时成立,只要证明对i = j+1也成立即可。
    * 对于第j+1个数,被选定概率是k/j+1,对于前j个数,必须在前j个数中被选定,且不被a[j+1]替换掉,才能
    最终被选定,由于i=j时成立,则前j个数被选定概率为k/j,不被替换分为两种情况,一种是a[j+1]不被选中,第二种是
    a[j+1]被选中但是没有替换掉该数,故p = k / j((1 - k /(j+1))+ k/(j+1) * (k-1)/k ) = k/j+1,可见对i=j+1中所有数
    都成立,从而得证。
    +Ps:怎么以k/j的概率选定第j个数呢,取n = random(1,j),如果n<=k则选定第j个数,可见这个概率是k/j。
原创粉丝点击