Reservoir Sampling 水塘抽样

水塘抽样是一组解决数据流取样的方法, 有很多的变种. 它适用的问题有如下特点:

  1. 对象为无法在内存中放下的数据, 如不间断数据流, 或者巨大的文件, 数组等.
  2. 样本集的大小为k, 并且要求每个样本的取样概率相等.
  3. 取样概率可以通过添加权重(weight)来改变取样概率.

一般(无weight)水塘抽样的每个样本的取样概率为: k/(n+1)

水塘抽样的算法实现非常简单, 而且证明简练. 算法如下:

  1. 预设数组A, 大小为k. 先取样k个元素. 放入A中.
  2. 从k+1元素开始, 每次取得随机数r, 范围为(0,k+1).
  3. 如果r <= k, A[r] = S[k+1], S是当前数据流.
public int[] sampling(InputStreamReader in, int k) throws IOException { int[] res = new int[k]; int cur = 0; Random random = new Random(); while (in.ready()) { int data = in.read(); if (cur<k){ res[cur] = data; } else { int r = random.nextInt(k+1); if (r < k) res[r] = data; } cur++; } return res; }