蓄水池算法简介

本文介绍了一种从大量数据流中随机选取k个数据的方法,并通过数学归纳法证明了该方法的有效性。

长度为N的数据流,要从中随机取得k个数据,N很大(可能大于你的内存和磁盘容量)且未知,只能遍历一次,求怎样可以取得完全随机的k个数据。

方法为:

1、定义一个长度为k的数组存储前k个数据

2、数据流流动,当输入的数据流的数据数量为i(k<i<N)时,取一个1到i的数字,如果生成的数字小于k,则把这个数字所对应的数组内的数字与i上的数进行交换。

完成这两步之后便可以实现在长度为N的数据流中取出k个随机数的目的了。


接下来将会证明对于N个数据,每个数据被取到的概率均为k/N。


证明:

采取数学归纳法证明对于输入i个数据(k<i<N)时,前i个数据被放入数组的概率都为k/i.

1、当i=k+1时,易得前i个数被放入数组的概率均为k/(k+1);

2、假设当i时,所有数据被放入数组的概率均为k/i.

3、证明当i+1时,所有数据被放入数组的概率均为k/(i+1)

首先对于第i+1个数据,显然它被放入数组的概率为k/(i+1)

对于前i个数据中的任意一个,它被放入数组的概率为k/i(由2),而它在输入第i+1个数据后仍然留在数组的概率应该为“它被输入到数组并且没有被第i+1个数据置换出来的概率”。

"被第i+1个数据置换出来的概率"此概率为((k/(i+1))*(1/k)=1/(i+1)

"没有被第i+1个数据置换出来的概率"此概率为1-1/(1+i)=i/(1+i)

“它被输入到数组并且没有被第i+1个数据置换出来的概率”此概率为k/i*(i/(1+i))=k/(1+i)

所以对于i+1个数据流,每一个数据被输入到数组的概率均为k/(1+i)

证明成功

蓄水池算法是一种大数据随机抽样算法,用于在未知数据规模($N$)的海量流式数据中随机选取$k$个样本,以达到均匀抽样的目的,即每个样本被选择的概率都是$\frac{k}{n}$。以下是对其的证明: ### 初始化阶段 算法开始时,用数据流中的前$k$个数来初始化一个容量为$k$的数组`a[k]`。此时,前$k$个元素进入蓄水池的概率为$1$,因为它们直接被放入了数组中。对于这$k$个元素,在当前阶段,它们被选中的概率$P_{1}=\frac{k}{k}=1$,满足概率要求。 ### 迭代阶段 当处理第$i$个元素($i > k$)时,会进行如下操作: 1. 在$[0, i]$之间随机生成一个整数$m$。 2. 如果$m < k$,则交换数组中`a[m]`和`a[i]`的元素。 下面分情况讨论第$i$个元素进入蓄水池的概率以及蓄水池中原有元素保留的概率: - **第$i$个元素进入蓄水池的概率**:在$[0, i]$之间随机生成一个数,这个数小于$k$的概率为$\frac{k}{i}$,所以第$i$个元素进入蓄水池的概率是$\frac{k}{i}$。 - **蓄水池中原有元素保留的概率**:对于蓄水池中已有的某个元素,它需要在第$i$次抽样时不被第$i$个元素替换掉。第$i$个元素进入蓄水池的概率是$\frac{k}{i}$,那么它不进入蓄水池的概率就是$1 - \frac{k}{i}$;如果第$i$个元素进入蓄水池,原有元素不被替换的概率是$\frac{k - 1}{k}$(因为进入蓄水池后,有$k$个位置,不替换到该元素的位置有$k - 1$个)。所以,在第$i$次抽样时,蓄水池中原有元素保留的概率为: - 当第$i$个元素不进入蓄水池时,概率为$1 - \frac{k}{i}$; - 当第$i$个元素进入蓄水池时,不替换原有元素的概率为$\frac{k}{i} \times \frac{k - 1}{k}$。 - 综合起来,原有元素保留的概率为$(1 - \frac{k}{i}) + \frac{k}{i} \times \frac{k - 1}{k} = \frac{i - k}{i} + \frac{k - 1}{i} = \frac{i - 1}{i}$。 ### 归纳法证明 假设在处理第$n - 1$个元素后,蓄水池中每个元素被选中的概率都是$\frac{k}{n - 1}$。当处理第$n$个元素时: - 对于第$n$个元素,它进入蓄水池的概率是$\frac{k}{n}$。 - 对于蓄水池中已有的元素,在处理第$n$个元素后,它保留的概率是在处理第$n - 1$个元素后被选中的概率$\frac{k}{n - 1}$乘以在第$n$次抽样时保留的概率$\frac{n - 1}{n}$,即$\frac{k}{n - 1} \times \frac{n - 1}{n} = \frac{k}{n}$。 通过数学归纳法,当处理完所有$N$个元素后,每个元素被选中进入蓄水池的概率都是$\frac{k}{N}$,从而证明了蓄水池算法可以实现均匀抽样。 ### 代码示例 以下是引用中给出的蓄水池算法的代码实现: ```cpp #include<iostream> #include<vector> using namespace std; // 从N个元素中等概率的选出K个 vector<int> sampling(int K, int N) { srand(time(NULL));//设置随机数种子,使每次产生的随机序列不同 if (N < 1 || K < 1 || N < K) { return {}; } //构建数组,需要把第i个数放入数组 vector<int> bag(K + 1); for (int i = 1; i <= K; i++) { // 前K个数据直接放进数组中 bag[i] = i; } // K+1个元素开始进行概率抽样 for(int i = K; i <=N; i++) { //剩下的数会有k/i的概率进入数组中, //产生从1~i的随机数,如果产生的随机数<=K,就说明中了概率 if ((rand() % i+1) <= K) { //替换的下标 int bagi = rand() % K + 1; bag[bagi] = i; } } return bag; } ```
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值