https://blog.csdn.net/huagong_adu/article/details/7619665

https://www.jianshu.com/p/63f6cf19923d

https://www.cnblogs.com/snowInPluto/p/5996269.html

https://www.cnblogs.com/xudong-bupt/p/4053652.html

https://www.jianshu.com/p/51f7089c082b

概念:

在一个给定长度的数组中随机等概率抽取一个数据很容易,但如果面对的是长度未知的海量数据流呢?蓄水池采样(Reservoir Sampling)算法就是来解决这个问题的, 它在分析一些大数据集的时候非常有用。

场景说明:

  1. 从一个字符流中进行采样,最后保留 10 个字符,而并不知道这个流什么时候结束,且须保证每个字符被采样到的几率相同。
  2. 应用场景场景说明:在一个海量广告数据中抽样100个query,其中特征包含pv(query的搜索次数)、adpv(出广告的搜索次数)、adshow(出广告之后的总共ad展示量)、click(点击数量)

蓄水池抽样:每次随机生成一个数(0,1)值u,令a = u(1/pv),循环n次,直到结束取前100个大的a值。

算法过程

  1. 假设原始数据规模为n,需要采样的数量为k
  2. 先选取数据流中的前k个元素,保存在集合A中;
  3. 从第j(k + 1 <= j <= n)个元素开始,每次先以概率p = k/j选择是否让第j个元素留下。若j被选中,则从A中随机选择一个元素并用该元素j替换它;否则直接淘汰该元素;
  4. 重复步骤3直到结束,最后集合A中剩下的就是保证随机抽取的k个元素。

数学归纳法证明:

  •    当n=k是,显然“蓄水池”中任何一个数都满足,保留这个数的概率为k/k。
  • 假设当n=m(m>k)时,“蓄水池”中任何一个数都满足,保留这个数的概率为k/m。
  • 当n=m+1时,以k/(m+1)的概率取An,并以1/k的概率,随机替换“蓄水池”中的某个元素,否则“蓄水池”数组不变。则数组中保留下来的数的概率为:

所以,对于第n个数An,以k/n的概率取An并以1/k的概率随机替换“蓄水池”中的某个元素;否则“蓄水池”数组不变。依次类推,可以保证取到数据的随机性。

Java实现的代码:

public class ReservoirSamplingTest {

    private int[] pool; // 所有数据
private final int N = 100000; // 数据规模
private Random random = new Random(); @Before
public void setUp() throws Exception {
// 初始化
pool = new int[N];
for (int i = 0; i < N; i++) {
pool[i] = i;
}
} private int[] sampling(int K) {
int[] result = new int[K];
for (int i = 0; i < K; i++) { // 前 K 个元素直接放入数组中
result[i] = pool[i];
} for (int i = K; i < N; i++) { // K + 1 个元素开始进行概率采样
int r = random.nextInt(i + 1);
if (r < K) {
result[r] = pool[i];
}
} return result;
} @Test
public void test() throws Exception {
for (int i : sampling(100)) {
System.out.println(i);
}
}
}

C++实现的代码:

int num = rand() % n +a;  //其中的a是起始值,n-1+a是终止值,n是整数的范围。

  //在序列流中取n个数,保证均匀,即取出数据的概率为:n/(已读取数据个数)
void RandKNum(int n){
int *myarray=new int[n];
for(int i=;i<n;i++)
cin>>myarray[i]; int tmp=;
int num=n;
while(cin>>tmp){
if(rand()%(num+)+<n)
myarray[rand()%n]=tmp;
} for(int i=;i<n;i++)
cout<<myarray[i]<<endl;
}

Reservoir Sampling 蓄水池采样算法的更多相关文章

  1. Reservoir Sampling 蓄水池抽样算法,经典抽样

    随机读取数据,如何保证真随机是不可能的,因为计算机的随机函数是伪随机的. 但是在不考虑计算机随机函数的情况下,如何保证数据的随机采样呢? 1.系统提供的shuffle函数 C++/Java都提供有sh ...

  2. Reservoir Sampling - 蓄水池抽样算法&&及相关等概率问题

    蓄水池抽样——<编程珠玑>读书笔记 382. Linked List Random Node 398. Random Pick Index 从n个数中随机选取m个 等概率随机函数面试题总结 ...

  3. 蓄水池采样算法(Reservoir Sampling)

    蓄水池采样算法 问题描述分析 采样问题经常会被遇到,比如: 从 100000 份调查报告中抽取 1000 份进行统计. 从一本很厚的电话簿中抽取 1000 人进行姓氏统计. 从 Google 搜索 & ...

  4. Reservoir Sampling - 蓄水池抽样问题

    问题起源于编程珠玑Column 12中的题目10,其描述如下: How could you select one of n objects at random, where you see the o ...

  5. Reservoir Sampling - 蓄水池抽样

    问题起源于编程珠玑Column 12中的题目10,其描述如下: How could you select one of n objects at random, where you see the o ...

  6. 【数据结构与算法】蓄水池抽样算法(Reservoir Sampling)

    问题描述 给定一个数据流,数据流长度 N 很大,且 N 直到处理完所有数据之前都不可知,请问如何在只遍历一遍数据(O(N))的情况下,能够随机选取出 m 个不重复的数据. 比较直接的想法是利用随机数算 ...

  7. leetcode398 and leetcode 382 蓄水池抽样算法

    382. 链表随机节点 给定一个单链表,随机选择链表的一个节点,并返回相应的节点值.保证每个节点被选的概率一样. 进阶:如果链表十分大且长度未知,如何解决这个问题?你能否使用常数级空间复杂度实现? 示 ...

  8. 【算法34】蓄水池抽样算法 (Reservoir Sampling Algorithm)

    蓄水池抽样算法简介 蓄水池抽样算法随机算法的一种,用来从 N 个样本中随机选择 K 个样本,其中 N 非常大(以至于 N 个样本不能同时放入内存)或者 N 是一个未知数.其时间复杂度为 O(N),包含 ...

  9. 蓄水池抽样算法 Reservoir Sampling

    2018-03-05 14:06:40 问题描述:给出一个数据流,这个数据流的长度很大或者未知.并且对该数据流中数据只能访问一次.请写出一个随机选择算法,使得数据流中所有数据被选中的概率相等. 问题求 ...

随机推荐

  1. Unity3D 原来Unity比较新的版本支持中文

    注意: Unity 2018.2 以上版本才可以

  2. Centos7安装gitlab11 学习笔记之基础概念、部署安装、权限管理、issue管理

    一.基础介绍 1.简介 一个基于GIT的源码托管解决方案 基于rubyonrails开发 集成了nginx postgreSQL redis sidekiq等组件 2.安装要求 2g内存以上,有点占内 ...

  3. webpack官网demo起步中遇到的问题

    在webpack官网demo一开始搭建中 

  4. javascript判断碰撞检测

    javascript判断碰撞检测 点与矩形的碰撞检测 <pre> /** * * @param x1 点 * @param y1 点 * @param x2 矩形view x * @par ...

  5. service 方法和doGet、doPost方法的区别

    Service方法和doGet和doPost方法的区别service:     可以处理get/post方式的请求,如果servlet 中有service方法,会优先调用service方法进行处理do ...

  6. 点击 显示红色 小案例 vue

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  7. 点亮文字(CSS)

    html <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8& ...

  8. order pick-up and delivery problem

    问题一: pi表示取第i个单,di表示送第i个单.di不能在pi的前面.给一个取单送单的顺序,问是否是valid顺序. public boolean isValidOrderList(List< ...

  9. Linux 时间以及时间间隔的简单处理.

    最近想知道自己的一个部署脚本的耗时, 中午时间看了一下最简单的Linux 时间函数的处理 我这里的处理非常简单, 仅仅是够用而已. 处理过程. 1. 获取当前时间: time1=`date` 或者是 ...

  10. SQL入门经典(第四版)学习记录——欢迎来到SQL世界(一)

    1.结构化查询语言——SQL,关系型数据库通信的标准语言: 2.关系型数据库:表的逻辑单元组成,这些表在内部彼此关联,组成了关系型数据库: 3.SQL会话:用户用SQL命令语句与关系型数据库进行交互时 ...