zoukankan      html  css  js  c++  java
  • 概率采样问题

    作者:jostree 转载请注明出处 https://www.cnblogs.com/jostree/p/10274908.html

    从n个数中等概率选取1个数,n未知

    如果元素总数是n,那么每个元素备选到的概率应该是1/n, 然而N只有遍历结束时才会知道,于是我们可以利用乘法公式凑出1/n:

    [p_i = frac{1}{i} imes frac{i}{i+1} imes frac{i+1}{i+2} imes dots imes frac{n-1}{n} = frac{1}{n} ]

    在从前向后遍历的过程中,不断的根据概率改变我们的候选元素,第i个元素被最终选中的概率计算公式恰好为上式。

    可以从代码简单实现:

    class RandomSelectOne
    {
        public:
            int count;
            int selected;
            RandomSelectOne():count(0){}
            void add(int num)
            {
                count++;
                if(rand() % count == 0)
                  selected = num;
            }
            int getSelected()
            {
                return selected;
            }
    }
    

    从n个数中等概率的选取m个数,n未知

    我们只需要把selected扩展成一个数组即可,对于第i个元素,其被选择的概率值为:

    [p_i = frac{m}{i} imes frac{i}{i+1} imes dots imes frac{n-1}{n} i > m ]

    [p_i = frac{1}{1} imes frac{m}{m+1} imes frac{m+1}{m+2} imes dots imes frac{n-1}{n} i leq m ]

    对于前m个数,直接加入候选,这个数出现在最终候选名单的概率为每次加入新的值时,该数都没有没选中。对于m以后的数,被选进来的概率为m/i,在以后每次加入新数时,都没有被选中,即可以有上式表示。

    代码如下:

    class RandomSelect
    {
        public:
            int count;
            int scount;
            vector<int> selected;
            RandomSelect(int m):count(0), scount(m){}
            void add(int num)
            {
                count++;
                if(selected.size() < scount)
                {
                    selected.push_back(num);
                }
                else
                {
                    int idx = rand() % count;
                    if( idx < scount )
                    {
                        selected[idx] = num;
                    }
                }
            }
            vector<int> getSelected()
            {
                return selected;
            }
    };
    

    带权的n个数随机选取一个数的问题,n未知

    设元素总数为n,当然在遍历结束前n是未知的。设第 (i(1 leq i leq n)) 个元素的权重为 (w_i) ,则权重总和为(w=sum_{i=1}^n w_i) ,也是在遍历结束时才知道的。根据题目要求,第(i)个元素被选取的概率应该等于(pi=frac{w_i}{w})

    如果最终被选择的是第i个元素,那么必须在遍历到它时,恰好被选中:

    [frac{w_i}{w} = frac{w_i}{sum_{k=1}^i w_k} ]

    另外,在处理后面的元素时,第i个元素没有被替换掉,对于任意的(j( i < j leq n )),第i个元素都不会被选中,其概率为:

    [frac{w-w_j}{w} = frac{sum_{k = 1} ^ {j - 1} w_k}{sum_{k = 1} ^ j w_k} ]

    从而第i个元素最终被选择的概率为:

    [p_i = frac{w_i}{sum_{k=1}^n w_i} ]

    代码如下:

    class RandomSelectOne
    {
        public:
            double totalWeight;
            int selected;
            RandomSelectOne():totalWeight(0.0){}
            void add(int num, double weight)
            {
                totalWeight += weight;
                if(rand() % 10000 / 10000.0 * totalWeight < weight)
                  selected = num;
            }
            int getSelected()
            {
                return selected;
            }
    };
    

    带权的n个数随机选取m个数,n未知

    当m=2时,第i个元素被选中有两种情况,第一次被选中,第一次未被选中,第二次被选中,从而可以得到:

    [p_i(2) = frac{w_i}{w} + sum_{j eq i} (frac{w_j}{w} imes frac{w_i}{w-w_j}) ]

    也可以计算(ar{p})表示不被选中的概率:

    [ar{p}_i(2) = sum_{j eq i} (frac{w_j}{w} imes frac{w - w_j - w_i}{w - w_j}) ]

    很容易得到(p_i(2) + ar{p}_i(2) = 1)

    当m>2时,元素i未被选中的概率为:

    [ar{p}_i(m) = sum_{j_1}(frac{w_{j_1}}{w} sum_{j_2} ( frac{w_{j_2}}{w-w_{j_1}} sum_{j_3} (frac{w_{j_2}}{w-w_{j_1}-w_{j_2}} dots sum_{j_m} frac{w_{j_m}}{w - sum_{k=1}^{m-1} w_{j_k}}))) ]

  • 相关阅读:
    mysql安装脚本
    vim常用命令
    CentOS 6.5使用国内网易163的源
    053(七十五)
    053(七十四)
    053(七十三)
    053(七十二)
    053(七十一)
    053(七十)
    053(六十九)
  • 原文地址:https://www.cnblogs.com/jostree/p/10274908.html
Copyright © 2011-2022 走看看