蓄水池抽样 Reservoir Sampling
Last updated
Was this helpful?
Last updated
Was this helpful?
作为数据从业者,数据的采样必不可少。
给定一个数据流,数据流长度N很大,且N直到处理完所有数据之前都不可知,请问如何在只遍历一遍数据(O(N))的情况下,能够随机选取出k个不重复的数据。
数据流长度N很大且不可知,所以不能直接取N内的k个随机数,然后按索引取出数据。
时间复杂度为O(N),所以不能先遍历一遍,然后分块存储数据,再随机选取。
随机选取k个数,每个数被选中的概率为k/N,必须保持数据选取绝对随机。
例如在一很大,但未知确实行数的文字档中抽取任意一行。如果要确保每一行抽取的几率相等,即是说如果最后发现文字档共有N行,则每一行被抽取的几率均为1/N
第n行被抽取的几率为1/n,以Pn表示。如果档案共有N行,任意第n行被抽取的几率为
因此,各行被抽取的几率均相同。
因为这个算法是动态的概率,概率不仅跟N有关,每次加载一行都有可能会影响已产生的结果。所以保证了概率均等。
也就是说,如果档案有 N >= k 行,则每一行被抽取的几率为 k/N
第n行被抽取的几率为k/n,以Pn表示。如果档案共有N行,任意第n行被抽取的几率为
伪代码:
如果遇到超大的数据量,即使是O(N)的时间复杂度,蓄水池抽样程序完成抽样任务也将耗时很久。因此分布式的蓄水池抽样算法应运而生。
运作原理如下:
假设有K台机器,将大数据集分成K个数据流
每台机器使用单机版蓄水池抽样处理一个数据流,抽样m个数据,并最后记录处理的数据量为N1, N2, ..., Nk, ..., NK(假设m < Nk)。其中N1+N2+...+NK=N。
取[1, N]一个随机数d,若d < N1,则在第一台机器的蓄水池中等概率不放回地(1/m)选取一个数据;若N1 <= d < (N1+N2),则在第二台机器的蓄水池中等概率不放回地选取一个数据;一次类推,重复m次,则最终从N大数据集中选出m个数据。
m/N的概率验证如下:
第k台机器中的蓄水池数据被选取的概率为m/Nk。
从第k台机器的蓄水池中选取一个数据放进最终蓄水池的概率为Nk/N。
第k台机器蓄水池的一个数据被选中的概率为1/m。(不放回选取时等概率的)
重复m次选取,则每个数据被选中的概率为m * (m / Nk * Nk / N * 1 / m)=m / N。