蓄水池抽样算法
作者:互联网
给定一个数据流,数据流长度N很大,且N直到处理完所有数据之前都不可知,请问如何在只遍历一遍数据(O(N))的情况下,能够随机选取出m个不重复的数据。
这个场景强调了3件事:
- 数据流长度N很大且不可知,所以不能一次性存入内存。
- 时间复杂度为O(N)。
- 随机选取m个数,每个数被选中的概率为m/N。
面试中被问到的概率题,才想起学习一下,这篇博客总体参考大佬的博客,但是在证明那里加入了自己的理解。
算法思路:
- 如果接收的数据量小于m,则依次放入蓄水池。
- 当接收到第i个数据时,i >= m,在[0, i]范围内取以随机数d,若d的落在[0, m-1]范围内,则用接收到的第i个数据去替换蓄水池中的第d个数据。
- 重复步骤2。
算法的精妙之处在于:当处理完所有的数据时,蓄水池中的每个数据都是以m/N的概率获得的。
算法证明:
第i个接收到的数据最后能够留在蓄水池中的概率=第i个数据进入过蓄水池的概率*之后的i+1~N操作里第i个数据不被替换的概率(第i+1到第N次处理 数据i都不会被替换)。
- 当i<=m时,数据直接放进蓄水池,所以第i个数据进入过蓄水池的概率=1。
- 当i>m时,在[1,i]内选取随机数d,如果d<=m,则使用第i个数据替换蓄水池中第d个数据,因此第i个数据进入过蓄水池的概率=m/i。
- 当i<=m时,程序从接收到第m+1个数据时开始执行替换操作,第m+1次处理会替换池中数据的概率为m/(m+1),在池中执行替换 替换掉第i个数据的概率为1/m,则第m+1次处理替换掉第i个数据的概率为(m/(m+1))*(1/m)=1/(m+1),不被替换的概率为1-1/(m+1)=m/(m+1)。依次,第m+2次处理不替换掉第i个数据概率为(m+1)/(m+2)...第N次处理不替换掉第i个数据的概率为(N-1)/N。所以,之后第i个数据不被替换的概率=m/(m+1)*(m+1)/(m+2)*...*(N-1)/N=m/N。
- 当i>m时,程序从接收到第i+1个数据时才开始有可能替换第i个数据。则参考上述第3点,第i+1个数据对蓄水池里的每个数据d进行替换的概率=m/(i+1) *1/m=1/(i+1),假设i在蓄水池中,i不被i+1替换的概率为1- 1/(i+1)=i/(i+1),所以之后的N-i个操作里第i个数据不被替换的概率=i/(i+1)*(i+1)/(i+2)*…*(N-1)/N=i/N。
- 结合第1点和第3点可知,当i<=m时,第i个接收到的数据最后留在蓄水池中的概率=1*m/N=m/N。结合第2点和第4点可知,当i>m时,第i个接收到的数据留在蓄水池中的概率=m/i*i/N=m/N。综上可知,每个数据最后被选中留在蓄水池中的概率为m/N。
标签:抽样,概率,蓄水池,算法,接收,数据,替换 来源: https://www.cnblogs.com/yh-blog/p/15222570.html