随机抽样java_Reservoir Sampling 蓄水池抽样算法,经典抽样

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

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

1.系统提供的shuffle函数

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

C++:

1 template

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 voidRandNum(){3 int res=0;4 int num=0;5 num=1;6 cin>>res;7

8 inttmp;9 while(cin>>tmp){10 if(rand()%(num+1)+1>num)11 res=tmp;12 num++;13 }14 cout<

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(intn){3 int *myarray=new int[n];4 for(int i=0;i>myarray[i];6

7 int tmp=0;8 int num=n;9 while(cin>>tmp){10 if(rand()%(num+1)+1

11 myarray[rand()%n]=tmp;12 }13

14 for(int i=0;i

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值