zoukankan      html  css  js  c++  java
  • Reservoir Sampling 蓄水池抽样算法,经典抽样

    随机读取数据,如何保证真随机是不可能的,因为计算机的随机函数是伪随机的。

    但是在不考虑计算机随机函数的情况下,如何保证数据的随机采样呢?

    1.系统提供的shuffle函数

      C++/Java都提供有shuffle函数,可以对容器内部的数据打乱,保持随机排序。

      C++:

    1 template <class RandomAccessIterator, class URNG>
    2   void shuffle (RandomAccessIterator first, RandomAccessIterator last, URNG&& g);

      Java:

    1 static void    shuffle(List<?> list);
    2 static void    shuffle(List<?> list, Random rnd);

      这些函数对数量一定的数据的随机打乱顺序,并不能处理数量不定的数据流。

    2.在序列流中取一个数,如何确保随机性,即取出某个数据的概率为:1/(已读取数据个数)

      假设已经读取n个数,现在保留的数是Ax,取到Ax的概率为(1/n)。

      对于第n+1个数An+1,以1/(n+1)的概率取An+1,否则仍然取Ax。依次类推,可以保证取到数据的随机性。

      数学归纳法证明如下:

        当n=1时,显然,取A1。取A1的概率为1/1。

               假设当n=k时,取到的数据Ax。取Ax的概率为1/k。

               当n=k+1时,以1/(k+1)的概率取An+1,否则仍然取Ax

        (1)如果取Ak+1,则概率为1/(k+1);

        (2)如果仍然取Ax,则概率为(1/k)*(k/(k+1))=1/(k+1)

      所以,对于之后的第n+1个数An+1,以1/(n+1)的概率取An+1,否则仍然取Ax。依次类推,可以保证取到数据的随机性。

      代码如下:

     1 //在序列流中取一个数,保证均匀,即取出数据的概率为:1/(已读取数据个数)
     2 void RandNum(){    
     3     int res=0;
     4     int num=0;
     5     num=1;
     6     cin>>res;
     7 
     8     int tmp;
     9     while(cin>>tmp){
    10         if(rand()%(num+1)+1>num)
    11             res=tmp;
    12         num++;
    13     }
    14     cout<<"res="<<res<<endl;
    15 }

    3.在序列流中取k个数,如何确保随机性,即取出某个数据的概率为:k/(已读取数据个数)

      建立一个数组,将序列流里的前k个数,保存在数组中。(也就是所谓的"蓄水池")

      对于第n个数An,以k/n的概率取An并以1/k的概率随机替换“蓄水池”中的某个元素;否则“蓄水池”数组不变。依次类推,可以保证取到数据的随机性。

      数学归纳法证明如下:

        当n=k是,显然“蓄水池”中任何一个数都满足,保留这个数的概率为k/k。

               假设当n=m(m>k)时,“蓄水池”中任何一个数都满足,保留这个数的概率为k/m。

               当n=m+1时,以k/(m+1)的概率取An,并以1/k的概率,随机替换“蓄水池”中的某个元素,否则“蓄水池”数组不变。则数组中保留下来的数的概率为:

     

      所以,对于第n个数An,以k/n的概率取An并以1/k的概率随机替换“蓄水池”中的某个元素;否则“蓄水池”数组不变。依次类推,可以保证取到数据的随机性。

      代码如下:

     1 //在序列流中取n个数,保证均匀,即取出数据的概率为:n/(已读取数据个数)
     2 void RandKNum(int n){
     3     int *myarray=new int[n];
     4     for(int i=0;i<n;i++)
     5         cin>>myarray[i];
     6 
     7     int tmp=0;
     8     int num=n;
     9     while(cin>>tmp){
    10         if(rand()%(num+1)+1<n)    
    11             myarray[rand()%n]=tmp;
    12     }
    13 
    14     for(int i=0;i<n;i++)
    15         cout<<myarray[i]<<endl;
    16 }
  • 相关阅读:
    Python while循环实现重试
    VBA find查找行号和列号的方法
    通过selenium控制浏览器滚动条
    【转】自然语言处理P,R,F值的计算公式
    【转】ultraedit 正则表达式
    【转】java文件输出流,写到.txt文件,如何实现换行
    Java heap space 解决方法
    XML+RDF——实现Web数据基于语义的描述(转载)
    java学习笔记——jsp简单方法读取txt文本数据
    一个完全独立的今天
  • 原文地址:https://www.cnblogs.com/xudong-bupt/p/4053652.html
Copyright © 2011-2022 走看看