随机采样——蓄水池采样算法

问题引入

有一个机器按自然数序列的方式吐出球,1号球,2号球,3号球等等。你没有更多的空间,一个球一旦扔掉,就再也不可拿回。设计一种选择方式,使得当机器吐出第N号球的时候,你袋子中的球数是K个,同时可以保证从1号球到N号球中的每一个,被选进袋子的概率都是K/N。

问题分析

对该问题进行数学建模,即从1-N的自然数序列中等概率抽取K个数,但N是很大或者未知的。对于这种问题最有效的方法就是我们本次要讲的蓄水池采样算法。

蓄水池采样算法

算法描述

  1. 使用一个长度为K的数组array保存抽取的数字。
  2. 对输入序列进行遍历,对于第i次遍历,其中1 ≤ i ≤ N,则:
    (1)当 i ≤ K 时,全部进行抽取,即array[i] = i
    (2)当 i > K 时,以 K / i 概率抽取,并且随机(等概率)替换掉已经抽取了的 K个数中其中的一个数。
  3. 遍历结束后,数组array中的元素就是最终抽取的数字。

算法证明

  • 对于第 i个数(i ≤ K)。在K步之前,所有数都会被选中,即被选中的概率为 1。当走到第 K+1步时,第i个数被第K+1个元素替换的概率为第K+1个元素被选中的概率 * 第i被选中替换的概率,即为\frac{K}{K+1} * \frac{1}{K} = \frac{1}{K+1}。则 i 被保留的概率为 1−\frac{1}{K+1}=\frac{K}{K+1}。依此类推,不被第K+2个元素替换的概率为 1-\frac{K}{K+2} * \frac{1}{K} = \frac{K+1}{K+2}。则运行到第 N 步时,第i个数被保留的概率 = 被选中的概率 * 不被替换的概率,即:
    1 * \frac{K}{K+1} * \frac{K+1}{K+2}* \frac{K+2}{K+3} * ... * \frac{N-1}{N} = \frac{K}{N}

  • 对于第j个数(j > K)。在第j步被选中的概率为\frac{K}{j}。不被j+1个元素替换的概率为 1 -\frac{K}{j+1} * \frac{1}{K} = \frac{j}{j+1}。则运行到第N步时,第j个数被保留的概率 = 被选中的概率 * 不被替换的概率,即:
    \frac{K}{j} * \frac{j}{j+1}* \frac{j+1}{j+2} * ... * \frac{N-1}{N} = \frac{K}{N}

综上所述,对于每个元素被保留的概率均为 \frac{K}{N}

算法实现

本文使用java语言实现蓄水池采样算法,如下:

import java.util.*;
public class RadomSelect {
    private int[] selected = null;
    private static Random rand = new Random(12345);

    // 每次拿一个球都会调用这个函数,N表示第i次调用
    public int[] carryBalls(int N, int k) {
        if (selected == null) {
            selected = new int[k];
        }
        if (N <= k) {
            selected[N - 1] = N;
        } else {
            if (rand.nextInt(N) < k) {
                int p = rand.nextInt(k);
                selected[p] = N;
            }
        }
        return selected;
    }

    public static void main(String[] args) {
        Bag bag = new Bag();
        int N = 1000;
        int k = 10;
        for (int i = 1; i <= N; i++) {
            bag.carryBalls(i, k);
        }
        System.out.println(Arrays.toString(bag.selected));
    }
}

总结

蓄水池采样算法适用于在总的样本数未知或者很大的情况下,对样本进行采样的问题。因此,蓄水池采样算法常用于大数据领域。

写在最后

欢迎大家关注我的个人博客复旦猿

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 蓄水池抽样算法(Reservoir Sampling) 许多年以后,当听说蓄水池抽样算法时,邱simple将会想起...
    邱simple阅读 75,810评论 7 86
  • 在一个给定长度的数组中随机等概率抽取一个数据很容易,但如果面对的是长度未知的海量数据流呢?蓄水池采样(Reserv...
    Astolfo阅读 663评论 0 0
  • 今天在网上看题目时,发现一个十分有趣的算法,叫蓄水池算法(Reservoir Sampling),牵扯到一点概率论...
    喵帕斯0_0阅读 2,194评论 0 2
  • Leetcode上遇到一道题,题目是这样的: 这道题的关键是链表的长度不知道,但是要使随机返回每个元素的概率相等,...
    文哥的学习日记阅读 7,570评论 0 8
  • 冬带着无限的眷恋 离开了他栖息梅花枝头最后一枚雪花 飘向远方。 肃静的大地,有了春的气息 十里桃花,你追我赶 奔赴...
    唐春元ok阅读 217评论 2 1