蓄水池抽样

1. 问题描述

给定一个长度很长的数据流,在处理完成之前不知道其具体长度,如何在遍历一遍数据流的情况下,随机地抽出m个不重复的数据。

key words:

  1. 长度很长,遍历完之前不可知;
  2. O(N)复杂度;
  3. 等概率地抽出m个数,每个数被抽中的概率为m/N。

2. 蓄水池抽样算法步骤

  1. 如果接收的数据量小于m,直接放入蓄水池reservoir
  2. 如果接收的数量大于m,假设是第i个数据,i>=m,则在[1,i]中随机选择一个数,假设为x,如果x<m,则将蓄水池reservoir[x]=datastream[i]
  3. 重复步骤2直到读取完数据流
vector<int> reservoir(m);//蓄水池中的m个元素
for(int i = 0; i < m; i++){
	reservoir[i] = datastream[i];
}
for(int i = m; i < datastream.size(); i++) {//这里不严谨,应该用指针或者输入流来控制循环条件
	srand(time(NULL));
	int j = randint(0, i);
	if (j < m)
		reservoir[j] = datastream[i];
}

3. 算法证明

如何保证每个数被抽到的概率为 m N \frac{m}{N} Nm
i个接收到的数据最后能够留在蓄水池中的概率=第i个数据进入过蓄水池的概率*之后第i个数据不被替换的概率(第i+1到第N次处理数据都不会被替换)。

  1. if(i <= m),第i个数据肯定可以进入过蓄水池,概率为1,我们还需要求出,第i个数后续一直不会被替换的概率;
  2. if(i <= m),第i个数据后续不被替换的概率怎么求?
    我们先求第i个数据被替换的概率。
    从第 m + 1 m+1 m+1个数开始,第i个数就有可能被替换啦,从 m + 1 m+1 m+1个数中抽一个数,抽到的数小于等于 m m m的概率为 m m + 1 \frac{m}{m+1} m+1m m m m个数中抽到的恰好是 i i i的概率为 1 m \frac{1}{m} m1 ,所以第 i i i个数被替换的概率为 m m + 1 ∗ 1 m = 1 m + 1 \frac{m}{m+1}*\frac{1}{m}=\frac{1}{m+1} m+1mm1=m+11.
    那么第 i i i个数不被替换的概率为 1 − 1 m + 1 = m m + 1 1-\frac{1}{m+1}=\frac{m}{m+1} 1m+11=m+1m
    对于第 m + 2 m+2 m+2个数,第 i i i个数不被替换的概率为 m + 1 m + 2 \frac{m+1}{m+2} m+2m+1
    以此类推,从第 m + 1 m+1 m+1一直到第 N N N个数,第 i i i个数一直不会被替换的概率为: m m + 1 ∗ m + 1 m + 2 ∗ . . . ∗ N − 1 N = m N \frac{m}{m+1}*\frac{m+1}{m+2}*...*\frac{N-1}{N}=\frac{m}{N} m+1mm+2m+1...NN1=Nm
  3. 综合1)2),当 i < = m i<=m i<=m时,第i个数据进入过蓄水池的概率*之后第i个数据不被替换的概率 = 1 ∗ m N = m N 1*\frac{m}{N}=\frac{m}{N} 1Nm=Nm
  4. if(i>m),第i个数进入蓄水池的概率为 m i \frac{m}{i} im,从第 i + 1 i+1 i+1个数开始,第i个数可能被替换出蓄水池,根据前面的结果,从第i+1一直到第N个数都不会替换第i个数的概率为: i i + 1 ∗ i + 1 i + 2 ∗ . . . ∗ N − 1 N = i N \frac{i}{i+1}*\frac{i+1}{i+2}*...*\frac{N-1}{N}=\frac{i}{N} i+1ii+2i+1...NN1=Ni
    于是第i个数留在蓄水池中的概率为 m i ∗ i N = m N \frac{m}{i}*\frac{i}{N}=\frac{m}{N} imNi=Nm

综上:蓄水池算法可以保证每个数被抽到的概率为 m N \frac{m}{N} Nm

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值