• 蓄水池算法 抽样统计


    对这个问题我们首先从最简单的例子出发:数据流只有一个数据。我们接收数据,发现数据流结束了,直接返回该数据,该数据返回的概率为1。看来很简单,那么我们试试难一点的情况:假设数据流里有两个数据。

            我们读到了第一个数据,这次我们不能直接返回该数据,因为数据流没有结束。我们继续读取第二个数据,发现数据流结束了。因此我们只要保证以相同 的概率返回第一个或者第二个数据就可以满足题目要求。因此我们生成一个 0 到 1 的随机数R,如果R小于 0.5 我们就返回第一个数据,如果R大于 0.5,返回第二个数据。

            接着我们继续分析有三个数据的数据流的情况。为了方便,我们按顺序给流中的数据命名为1、2、3。我们陆续收到了数据1、2 和前面的例子一样,我们只能保存一个数据,所以必须淘汰 1 和 2 中的一个。应该如何淘汰呢?不妨和上面例子一样,我们按照二分之一的概率淘汰一个,例如我们淘汰了 1. 继续读取流中的数据3,发现数据流结束了,我们知道在长度为 3 的数据流中,如果返回数据 3 的概率为1/3 那么才有可能保证选择的正确性。也就是说,目前我们手里有1,3 两个数据,我们通过一次随机选择,以1/3 的概率留下数据3,以2/3 的概率留下数据 1. 那么数据 1 被最终留下的概率是多少呢?

    • 数据 1 被留下:(1/2)*(2/3) = 1/3
    • 数据 2 被留下概率:(1/2)*(2/3) = 1/3
    • 数据 3 被留下概率:1/3

            这个方法可以满足题目要求,所有数据被留下返回的概率一样!

            因此,我们做一下推论:假设当前正要读取第n个数据,则我们以1/n的概率留下该数据,否则留下前n-1 个数据中的一个。以这种方法选择,所有数据流中数据被选择的概率一样。简短的证明:假设n-1 时候成立,即前n-1 个数据被返回的概率都是1/n-1,当前正在读取第n个数据,以1/n的概率返回它。那么前n-1 个数据中数据被返回的概率为:(1/(n-1))*((n-1)/n)= 1/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

    证明每个数被取到的概率为k/n:

        1. 对于第i个数(i<k),在前k步被选中的概率是1, 从第k+1步开始,i不被选中的概率为k/k+1,那么读到第n个数时, 第i个数(i<k)被选中的概率 = 被选中的概率 * 以后每一步都不被换走的概率,即
          1 * k/k+1 * k+1/k+2 n-1/n = k/n

        2. 对于第j个数(j>=k)被选中的概率为: 在他出现时被选中的概率 * 在他出现以后不被换走的概率,即: 
          k/j * j /j+1 。。。n-1/n = k/n

        3. 综上得证。

  • 相关阅读:
    《RabbitMQ 实战》读书笔记
    使用jstack命令查看CPU高占用的问题记录
    两种常见的单元测试方式(笔记)
    Apache Solr入门教程(转)
    搜索引擎选择: Elasticsearch与Solr(转)
    CopyOnWriteArrayList与Collections.synchronizedList的性能对比(转)
    理解list和vector的区别
    从上往下打印出二叉树的每个节点,同层节点从左至右打印。
    TypeError: Object function (req, res, next) { app.handle(req, res, next); } has no method 'configure'
    Cannot find module 'crc'
  • 原文地址:https://www.cnblogs.com/hexie/p/4961564.html
Copyright © 2020-2023  润新知