1、问题描述分析

采样问题经常会被遇到,比如:

1、从 100000 份调查报告中抽取 1000 份进行统计;
2、从一本很厚的电话簿中抽取 1000 人进行姓氏统计;
3、从 Google 搜索 "Ken Thompson",从中抽取 100 个结果查看哪些是今年的。

既然说到采样问题,最重要的就是做到公平,也就是保证每个元素被采样到的概率是相同的。所以可以想到要想实现这样的算法,就需要掷骰子,也就是随机数算法。(这里就不具体讨论随机数算法了,假定我们有了一套很成熟的随机数算法了)

对于第一个问题,还是比较简单,通过算法生成 [0,100000−1)[0,100000−1) 间的随机数 1000 个,并且保证不重复即可。再取出对应的元素即可。

但是对于第二和第三个问题,就有些不同了,我们不知道数据的整体规模有多大。可能有人会想到,我可以先对数据进行一次遍历,计算出数据的数量 N,然后再按照上述的方法进行采样即可。这当然可以,但是并不好,毕竟这可能需要花上很多时间。也可以尝试估算数据的规模,但是这样得到的采样数据分布可能并不平均。

2、蓄水池算法

终于要讲到蓄水池采样算法(Reservoir Sampling)了。先说一下算法的过程:

1、假设数据序列的规模为 n,需要采样的数量的为 k。

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

3、然后从第 k+1 个元素开始,以 k/n 的概率来决定该元素最后是否被留在数组中(每进来一个新的元素,数组中的每个旧元素被替换的概率是相同的)。 当遍历完所有元素之后,数组中剩下的元素即为所需采取的样本。

  • 证明过程

第 1 种情况:对于数组中第 i 个数据(i ≤ k)。在 k 步之前,被选中的概率为 1。当走到第 k+1 步时,被第 k+1 个数据替换的概率 = 第k+1个元素被选中的概率 * 第i个数 被选中替换的概率,即为 。则被保留的概率为 。依次类推,在不被第 k + 1 个元素替换的前提下,不被第k+2 个数据替换的条件概率为。则运行到第 n 步时,被保留的概率 = 被选中的概率 * 不被替换的概率,即(条件概率的连乘):

第 2 种情况:对于第 j 个数据(j > k)。第 j个数据被选中的概率为 k / j。不被第 j + 1 个元素替换的概率为 。则运行到第 n步时,被保留的概率 = 被选中的概率 * 不被替换的概率,即条件概率的连乘):

  • 所以对于其中每个元素,被保留的概率都为 k/n。

3、代码实现

public class ReservoirSampling {// 从N个元素中等概率的选出K个public static int[] sampling(int K, int N){if(N < 1 || K < 1 || N < K){return null;}// 初始化所有数据int[] arr = new int[N];for(int i = 0; i < N; i++){arr[i] = i;}int[] pool = new int[K];for(int i = 0; i < K; i++){// 前K个数据直接放进数组中pool[i] = arr[i];}Random random = new Random();// K+1个元素开始进行概率抽样for(int i = K; i < N; i++){// 等概率的返回下标为 0-i中的一个int index = random.nextInt(i + 1);if(index < K){// 用pool[i]替换掉res[index],index是随机等概率选中的pool[index] = arr[i];}}return pool;}public static void main(String[] args) {System.out.println(Arrays.toString(sampling(20, 10000)));}
}

【搞定算法】蓄水池算法相关推荐

  1. 背包算法轻松搞定——01背包算法、部分背包算法

    这篇文章过程讲得很详细,一文搞懂(点击看原文) 不懂之前觉得很难理解,觉得很复杂,其实没有必要.因为只要懂动态规划就可以很轻松搞定0-1背包算法(部分背包算法更简单,排序即可).之前看了很多篇文章都觉 ...

  2. [经验分享] 覃超线上直播课 如何快速搞定秋招算法面试

    本文为作者关于覃超在2020年07月12日的线上直播课的学习笔记. 再次强调 不要死磕.不要对于写的又臭又长又充满bug的代码,不停的打补丁.就算最后花费大力气通过了,也没什么进步.因为这时候已经耗干 ...

  3. 十分钟搞定时间复杂度(算法的时间复杂度)

    目录 一.什么是时间复杂度 二.时间复杂度的计算 单个循环体的推导法则 多重循环体的推导法则 多个时间复杂度的推导法则 条件语句的推导法则 习题练习 一.基础题 二.进阶题 三.再次进阶 一.什么是时 ...

  4. 一文搞定选择排序算法

    一.选择排序 本次内容概要: 1.选择排序原理 选择排序是一种比较简单而且直观的排序算法,它的工作原理是每一次从待排序的数据元素中选出最小或者最大的元素,存放在序列的起始位置,直到全部待排序的数据元素 ...

  5. 300分钟搞定数据结构与算法课程学习1

  6. 最短时间搞定算法:字节跳动Android岗算法题考前突击宝典

    前言 一个人,一支笔,一个晚上,一个奇迹.这是学生党的常规操作. 大学里也同样有很多奇迹的创造者:每次一到期末考试的前几个晚上,各个变身"最强大脑",上知天文,下晓地理,还精通人文 ...

  7. python3 锦鲤第一步!了解随机抽样之蓄水池算法

    python3 锦鲤第一步!了解随机抽样之蓄水池算法 蓄水池算法 问题背景: 样本空间为N,从N个样本中随机不重复地抽取K个样本,其中N是未知且非常巨大的数,如何保证每个样本是等概率被抽取才是关键. ...

  8. 算法:算法概述【时间复杂度、空间复杂度】

    一.算法定义 算法:为了实现业务目的的各种方法和思路就是算法.同样的数据,同样的目的, 不同的算法,不同的方法和思路,效率就会不同 算法是一种独立的存在 , 它并不依附于代码 , 代码只是实现算法思想 ...

  9. 如何搞定不同公司的算法面试?(早早聊分享文字版)

    前几天西法参加了<前端早早聊>第 24 界的分享.我的分享主题是<如何搞定不同公司的算法面试?> 这是这次分享的文字版,供大家查看.如果大家需要分享的原版 ppt,也可以到我的 ...

最新文章

  1. python螺旋打印二维数组_Python使用迭代器打印螺旋矩阵的思路及代码示例
  2. mxnet java 例子_mxnet(gluon) 实现DQN简单小例子
  3. 牛客网——数字求和(水题
  4. 简单使用CXF实现webserver(rs的独立发布)
  5. java 对 redis 的基本操作
  6. django-后台管理
  7. TIOBE 2 月编程语言排行榜:Objective-C 的出路在何方?
  8. linux 零拷贝golden,GoldenGate碎碎念
  9. 北京地铁挤,最挤昌平线
  10. MCS-51单片机的外部引脚及片外总线
  11. 微信公号开发之自定义菜单攻略
  12. 采购供应链管理系统:企业采购与供应链管理更简单、快捷
  13. 六.期货期权及其他金融衍生品(投资分析)
  14. java绘制菱形平行四边形_Java实现金字塔形菱形平行四边形
  15. CSS实现最简洁的加载动画
  16. 06.图像识别与卷积神经网络------《Tensorflow实战Google深度学习框架》笔记
  17. 混合IP-SDN环境的仿真实验
  18. 微信视频号怎么运营?实操分享我的30个经验
  19. 常见的端口漏洞入侵主机
  20. 软件自动化测试项目总结,自动化测试总结报告.docx

热门文章

  1. 西电计科数据库系统期末复习笔记
  2. php实现ctrl+f,Ctrl+F 到底有多好用?这 5 个骚操作,让你变身快捷键达人
  3. Google earth 生成研究区适量边界(研究区边界从哪来?)
  4. xilinx platform cable usb驱动_小白入门多路高速(8 x 8bits x 100Msps)AD驱动设计专栏启动预告...
  5. 【动手学深度学习】李沐——循环神经网络
  6. 30系列显卡安装深度学习pytorch坏境
  7. mt9638和t972哪个好
  8. turtle库——绘制八边形、八角图形以及叠边形图形
  9. c语言strtok用法详细解释
  10. 软件设计师证书重要吗?