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

作者: 复旦猿 | 来源:发表于2019-05-30 20:42 被阅读0次

问题引入

有一个机器按自然数序列的方式吐出球,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 时,以 i / K 概率抽取,并且随机(等概率)替换掉已经抽取了的 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));
    }
}

总结

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

写在最后

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

相关文章

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

    问题引入 有一个机器按自然数序列的方式吐出球,1号球,2号球,3号球等等。你没有更多的空间,一个球一旦扔掉,就再也...

  • 蓄水池采样算法

    解决问题:在不知道数据规模n的前提下,实现以的概率去数据进行采样思路:首先设计容量为k的容器C,把前k个元素放入,...

  • 【SQL】抽样

    随机采样 分层采样 hash 版 非hash 版

  • 😆 机器学习采样方法大全

    ? Index 数据采样的原因 常见的采样算法 失衡样本的采样 采样的Python实现 ? 数据采样的原因 其实我...

  • 不平衡样本的处理方法

    欠采样: 从多数类的样本中随机选择样本; 过采样: 复制少数类样本扩大数据集, smote算法及其衍生; 代价敏感...

  • 点云采样

    原文链接 点云采样分类 点云采样的方法有很多种,常见的有均匀采样,几何采样,随机采样,格点采样等。下面介绍一些常见...

  • 蓄水池采样

    现在有一组数,不知道这组数的总量有多少,请描述一种算法能够在这组数据中随机抽取k个数,使得每个数被取出来的概率相等...

  • SMOTE过采样

    SMOTE(合成少数类过采样),是基于随机过采样方法的一种改机方案。随机过采样通过简单复制样本的方式来增加少数样本...

  • 蓄水池采样算法-Lua版本

    由于业务需要,所以搜索了一些相关的随机算法代码是参考维基百科进行编写的:https://en.wikipedia....

  • 蓄水池采样算法-Reservoir Sampling

    前言 在刷Leetcode的过程种,遇到过不少类似的问题:给出一个链表,如何从中随机获取一个节点?直观的解法是把链...

网友评论

    本文标题:随机采样——蓄水池采样算法

    本文链接:https://www.haomeiwen.com/subject/hqkbtctx.html