这就是所谓的蓄水池抽样算法。它在分析一些大数据集的时候非常有用。你可以在这里找到 Greg 写的关于蓄水池抽样的算法介绍。本文后面会介绍一下在 Cloudera ML 中使用的两种:分布式蓄水池抽样和加权分布式蓄水池抽样。
(注:Cloudera ML 是基于 hadoop 的数据分析和挖掘开源项目)
蓄水池抽样在 Cloudera ML 上的应用
分布式蓄水池抽样是 Greg 讨论的第一种算法。可以从前面的讨论中发现,基本的蓄水池抽样要求对数据流进行顺序读取。要进行容量为k的分布式蓄水池抽样(前面讨论的容量都为1)我们使用 mapreduce 模拟 sql 中的 ORDER BY RAND (随机抽取)。对于集合中的每一个元素,都产生一个0-1 的随机数,之后选取随机值最大的前k个元素。这种方法在对大数据集进行分层抽样的时候非常管用。这里每一个分层都都是一些分类变量如性别,年龄,地理信息等的组合。注意如果输入的数据集分布极端的不均匀,那么抽样可能不能覆盖到所有的层级。为了对每种分类的组合进行抽样,cloudera ML 提供了 sample 命令,它可以操作纯文本或者 hive 中的表。
第二个算法更加好玩:加权分布式蓄水池抽样。这里集合中的数据是有权重的,算法希望数据被抽样选中的概率和该数据的权重成比例。实际上这个问题之前并不一定有解,直到 2005 年 pavlos efraimidis 和 paul spirakis 的论文《weighted random sampling with a reservoir》。他们的解法既简单又优雅,基本思想和上面的分布式蓄水池抽样一致:对于每个数据计算一个0-1 的值R,并求r的n次方根作为该数据的新的R值。这里的n就是该数据的权重。最终算法返回前k个R值最高的数据然后返回。根据计算规则,权重越大的数据计算所得的R值越接近1,所以越有可能被返回。
在 cloudera ML 项目中,为了更好地使用k-means++算法(K-均值++算法),我们会首先使用加权的蓄水池抽样算法对输入数据进行抽样。ksketch 命令会为k-means++算法进行初始化–在输入数据上进行迭代操作,选择样本抽样。每次选取过程,数据被选入样本的概率和该数据与当前样本中最短距离节点的距离成比例。通过使用加权的蓄水池抽样算法,只需扫描数据一遍就能决定样本组成(一般方法需要首先遍历一次以计算出聚类的总代价,之后第二次遍历根据第一次的计算结果进行样本选择)。