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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM