[Alg] 随机抽样完备算法-蓄水池算法 Reservoir Sampling

1. 问题定义

在保证$n$个元素被抽取的概率是相同的前提下,从总量为$n$的样本空间中随机抽取$k$个元素

2. 应用场景和一般算法

(1) 对于总数$n$值已知的情况

我们可以用最简单的随机数算法,生成范围在 $[1, n]$间的$k$个随机数。

(2) 对于总数$n$值提前未知的情况

一种方法是,首先遍历这个样本空间下所有样本并计数,得到n,之后再用(1)中的方法等随机抽样。

但是先遍历一遍样本空间,在样本很大的情况下是很耗时的。有没有不需要提前遍历一遍整个样本空间的,又能公平抽样的算法呢?

这里将介绍蓄水池算法,是一个被证明绝对公平的,不需提前预知样本空间大小的抽样算法。

(3) 实际场景

什么时候是"总数提前未知且要求随机抽样"的场景呢?

ex1. 从一本很厚的电话簿中抽取 1000 人进行姓氏统计

ex2. 从 Google 搜索 "Ken Thompson",从中抽取 100 个结果查看哪些是今年的

ex3. 我自己的实际工作场景:在推词工作中,要对最终项目产出的推荐词进行相关性评估,即评估推荐词和已购词的相关性。这里需要抽取,比如300条case人工评定一下相关性。那这里我们词库中的词太多啦,在hdfs中保存成了几千的part。要怎么对这么多数据随机抽取300条呢?

最初自己的想法是随机选几个part, 把随机取的几个part拼接,之后用随机数算法抽取。

但是有个问题,由于hadoop的工作原理,在reduce阶段把key相同/相近的放在一起了,使得保存在集群上的各个part间的数据可能不是完全独立的,并且不同part包含的数据量也可能不同。那在第一步随机选part这个阶段就不能保证完全公平了。虽然这个粗糙的方法也不太伤大雅,但是有更好的算法就可以学着用一下~

扫描二维码关注公众号,回复: 11386771 查看本文章

3. 蓄水池算法抽样过程

假设数据序列的规模为n, 需要采样的数量为$k$. 

首先构建一个可容纳$k$个元素的数组,将序列的前$k$个元素放入数组中。

然后从第$k + 1$个元素开始,以$\frac{k}{n}$的概率来决定该元素是否被替换到数组中 (数组中的元素被替换的概率是相同的)。

当遍历完所有元素后,数组中剩下的元素即为所需采样的样本。

4. 证明

(1) 对于第$i$个数 ($i <= k$)

(i) 在第$1, ..., k$步,该元素被选中到蓄水池数组的概率为1.

(ii) 在第$k+1$步,数据序列规模为$k + 1$.

该元素被替换的概率 = $k + 1$个元素被选中的概率 * $i$被选中替换的概率 = $\frac{k}{k + 1} \times \frac{1}{k} = \frac{1}{k + 1}$

该元素被保留的概率 = $1 - \frac{1}{k + 1} = \frac{k}{k + 1}$

(iii) 在第$k+2$步,数据序列规模为$k + 2$.

该元素不被第$k + 1$个元素替换(被保留)的概率 = $1 - \frac{k}{k + 2} \times \frac{1}{k} = \frac{k + 1}{k + 2}$

(iv) 第$n$步,该元素被保留的概率

$$1 \times \frac{k}{k + 1} \times \frac{k + 1}{k + 2} \times ... \times \frac{n - 1}{n} = \frac{k}{n} $$

(2) 对于第$j$个数 ($j > k$)

在第$j$步被选中的概率为$\frac{k}{j}$。

在第$j + 1$步,不被$j + 1$个元素替换的概率为$1 - \frac{k}{j + 1} \times \frac {1}{k} = \frac{j}{j + 1}$。

在第$j + 2$步,不被$j + 2$个元素替换的概率为$1 - \frac{k}{j + 2} \times \frac {1}{k} = \frac{j + 1}{j + 2}$

运行到第$n$步,该元素被保留的概率

$$1 \times \frac{j}{j + 1} \times \frac{j + 1}{j + 2} \times ... \times \frac{n - 1}{n} = \frac{k}{n}$$

因此,对于这$n$个元素,被保留的概率均为$\frac{k}{n}$。

参考链接:https://www.cnblogs.com/snowInPluto/p/5996269.html

猜你喜欢

转载自www.cnblogs.com/shiyublog/p/13204701.html