Spark MLlib之水塘抽样算法(Reservoir Sampling)
1.理解
问题定义可以简化如下:在不知道文件总行数的情况下,如何从文件中随机的抽取一行?
首先想到的是我们做过类似的题目吗?当然,在知道文件行数的情况下,我们可以很容易的用C运行库的rand函数随机的获得一个行数,从而随机的取出一行,但是,当前的情况是不知道行数,这样如何求呢?我们需要一个概念来帮助我们做出猜想,来使得对每一行取出的概率相等,也即随机。这个概念即蓄水池抽样(Reservoir Sampling)。
水塘抽样算法(Reservoir Sampling)思想:
在序列流中取一个数,如何确保随机性,即取出某个数据的概率为:1/(已读取数据个数)
假设已经读取n个数,现在保留的数是Ax,取到Ax的概率为(1/n)。
对于第n+1个数An+1,以1/(n+1)的概率取An+1,否则仍然取Ax。依次类推,可以保证取到数据的随机性。
数学归纳法证明如下:
当n=1时,显然,取A1。取A1的概率为1/1。
假设当n=k时,取到的数据Ax。取Ax的概率为1/k。 当n=k+1时,以1/(k+)的概率取An+,否则仍然取Ax。
(1)如果取Ak+1,则概率为1/(k+1);
(2)如果仍然取Ax,则概率为(1/k)*(k/(k+1))=1/(k+1)
所以,对于之后的第n+1个数An+1,以1/(n+1)的概率取An+1,否则仍然取Ax。依次类推,可以保证取到数据的随机性。
在序列流中取k个数,如何确保随机性,即取出某个数据的概率为:k/(已读取数据个数)
建立一个数组,将序列流里的前k个数,保存在数组中。(也就是所谓的”蓄水池”)
对于第n个数An,以k/n的概率取An并以1/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的概率随机替换“蓄水池”中的某个元素;否则“蓄水池”数组不变。依次类推,可以保证取到数据的随机性。
Spark中的水塘抽样算法(Reservoir Sampling)
spark的Partitioner子类RangePartitioner中有用到Reservoir Sampling抽样算法(org.apache.spark.RangePartitioner#sketch).
spark的util中有reservoirSampleAndCount方法(org.apache.spark.util.random.SamplingUtils#reservoirSampleAndCount)
源码为:
/**
* Reservoir sampling implementation that also returns the input size.
*
* @param input input size
* @param k reservoir size
* @param seed random seed
* @return (samples, input size)
*/
def reservoirSampleAndCount[T: ClassTag](
input: Iterator[T],
k: Int,
seed: Long = Random.nextLong())
: (Array[T], Int) = {
val reservoir = new Array[T](k)
// Put the first k elements in the reservoir.
var i =
while (i < k && input.hasNext) {
val item = input.next()
reservoir(i) = item
i +=
} // If we have consumed all the elements, return them. Otherwise do the replacement.
if (i < k) {
// If input size < k, trim the array to return only an array of input size.
val trimReservoir = new Array[T](i)
System.arraycopy(reservoir, , trimReservoir, , i)
(trimReservoir, i)
} else {
// If input size > k, continue the sampling process.
val rand = new XORShiftRandom(seed)
while (input.hasNext) {
val item = input.next()
val replacementIndex = rand.nextInt(i)
if (replacementIndex < k) {
reservoir(replacementIndex) = item
}
i +=
}
(reservoir, i)
}
}
代码实现思路比较简单,新建一个k大小的数组reservoir,如果元数据中数据少于k,直接返回原数据数组和原数据个数。如果大于,则对接下来的元素进行比较,随机生成一个数i,如果这个数小于k,则替换数组reservoir中第i个数,直至没有元素,则返回reservoir的copy数组。
2.代码:
测试org.apache.spark.util.random.SamplingUtils$#reservoirSampleAndCount方法:
package org.apache.spark.sourceCode.partitionerLearning import org.apache.spark.util.SparkLearningFunSuite
import org.apache.spark.util.random.SamplingUtils import scala.util.Random class reservoirSampleAndCountSuite extends SparkLearningFunSuite {
test("reservoirSampleAndCount") {
val input = Seq.fill()(Random.nextInt())
val (sample1, count1) = SamplingUtils.reservoirSampleAndCount(input.iterator, )
assert(count1 === )
assert(input === sample1.toSeq) // input size == k
val (sample2, count2) = SamplingUtils.reservoirSampleAndCount(input.iterator, )
assert(count2 === )
assert(input === sample2.toSeq) // input size > k
val (sample3, count3) = SamplingUtils.reservoirSampleAndCount(input.iterator, )
assert(count3 === )
assert(sample3.length === )
println(input)
sample3.foreach{each=>print(each+" ")}
} }
3.结果:
List(, , -, -, , -, , -, , , -, -, , -, -, , -, -, -, -, -, -, -, , -, , , , -, -, -, -, , , , , , -, , , -, , , -, -, -, -, -, -, -, , , -, , -, , , , , , -, , , -, , , , , -, , , , -, -, , -, , , , -, , -, , -, -, -, , , , , , , -, -, , -, , , -, -)
- - - -
Spark MLlib之水塘抽样算法(Reservoir Sampling)的更多相关文章
- 【算法34】蓄水池抽样算法 (Reservoir Sampling Algorithm)
蓄水池抽样算法简介 蓄水池抽样算法随机算法的一种,用来从 N 个样本中随机选择 K 个样本,其中 N 非常大(以至于 N 个样本不能同时放入内存)或者 N 是一个未知数.其时间复杂度为 O(N),包含 ...
- 蓄水池抽样算法 Reservoir Sampling
2018-03-05 14:06:40 问题描述:给出一个数据流,这个数据流的长度很大或者未知.并且对该数据流中数据只能访问一次.请写出一个随机选择算法,使得数据流中所有数据被选中的概率相等. 问题求 ...
- Spark MLlib中KMeans聚类算法的解析和应用
聚类算法是机器学习中的一种无监督学习算法,它在数据科学领域应用场景很广泛,比如基于用户购买行为.兴趣等来构建推荐系统. 核心思想可以理解为,在给定的数据集中(数据集中的每个元素有可被观察的n个属性), ...
- spark.mllib源代码阅读-优化算法1-Gradient
Spark中定义的损失函数及梯度,在看源代码之前,先回想一下机器学习中定义了哪些损失函数,毕竟梯度求解是为优化求解损失函数服务的. 监督学习问题是在如果空间F中选取模型f作为决策函数.对于给定的输入X ...
- 水塘抽样(Reservoir Sampling)问题
水塘抽样是一系列的随机算法,其目的在于从包含n个项目的集合S中选取k个样本,其中n为一很大或未知的数量,尤其适用于不能把所有n个项目都存放到主内存的情况. 在高德纳的计算机程序设计艺术中,有如下问题: ...
- Reservoir Sampling - 蓄水池抽样问题
问题起源于编程珠玑Column 12中的题目10,其描述如下: How could you select one of n objects at random, where you see the o ...
- 算法系列:Reservoir Sampling
copyright © 1900-2016, NORYES, All Rights Reserved. http://www.cnblogs.com/noryes/ 欢迎转载,请保留此版权声明. -- ...
- Reservoir Sampling - 蓄水池抽样
问题起源于编程珠玑Column 12中的题目10,其描述如下: How could you select one of n objects at random, where you see the o ...
- 用Spark学习矩阵分解推荐算法
在矩阵分解在协同过滤推荐算法中的应用中,我们对矩阵分解在推荐算法中的应用原理做了总结,这里我们就从实践的角度来用Spark学习矩阵分解推荐算法. 1. Spark推荐算法概述 在Spark MLlib ...
随机推荐
- Android 安全机制
转:http://www.cnblogs.com/GnagWang/archive/2011/03/21/1990507.html 1 Android 安全机制概述 Android 是一个权限分离的系 ...
- day_5.25py
作用域
- simulation vs emulation
Hardware emulation, the use of special purpose hardware to emulate the behavior of a yet-to-be-built ...
- 《JAVA编程思想》第四版 PDF 下载 中文版和英文版 高清PDF扫描带书签
一.链接: 中文版: https://pan.baidu.com/s/1d07Kp4 密码:x2cd 英文版: https://pan.baidu.com/s/1boOSdAZ 密码: rwgm 文件 ...
- java整形数据和浮点型数据
在定义数据的时候,如果有不是整形的数据(单精度,双精度之类的),那么运算的时候要在其所在式子里的数据后面加上.0,否则会出现(1/2=0.1.0/2=0.5)的现象,比如如下代码 public cla ...
- [No0000136]6个重要的.NET概念:栈,堆,值类型,引用类型,装箱,拆箱
引言 本篇文章主要介绍.NET中6个重要的概念:栈,堆,值类型,引用类型,装箱,拆箱.文章开始介绍当你声明一个变量时,编译器内部发生了什么,然后介绍两个重要的概念:栈和堆:最后介绍值类型和引用类型,并 ...
- iOS 添加第三方.framework 打包上传iTunesConnect 遇到的坑
1.添加完第三方库,模拟器运行没事,打iOS通用设备包的时候报一个错. ld: '/Users/jiangwei.wang/Documents/Project/APP NAME/SeosMobileK ...
- [bigdata] palantir
Palantir的无缝数据融合技术关键在于本体数据模型的灵活性,动态性,而且要能反映人.事.物和环境的关联关系及因果联系,这是大数据技术面临的核心挑战.
- isprime_判断质数
判断质数的方法有很多,首先是最简单的试除法,判断n以内的质数的话时间复杂度为n*sqrt(n)当然是很慢的了 下面提供三种判断质数的方法: 首先是跑5051ms的这个是埃拉托斯特尼筛法 且不加优化 核 ...
- 使用TidCookieManager得到cookie
1.拖入TIdHTTP控件,HandleRedirect设为True,否则可能会出现HTTP 307错误. 2.主要的设置在Request里. 2.1 userAgent应该改为Mozilla/4.0 ...