Map-Reduce实现中的一种特殊示例方法

时间:2014-12-04 06:14:25

标签: algorithm hadoop mapreduce sample random-sample

我有一张4 * 10 ^ 8(大致)记录的表格,我希望得到一个4 * 10 ^ 6(完全)的样本。

但我获取样本的方式有点特别:

  1. 我随机从4 * 10 ^ 8记录中选择1条记录(每条记录的概率都相同)。
  2. 重复步骤1 4 * 10 ^ 6次(无论多次选择一条记录)。
  3. 我想到了解决这个问题的方法:

    1. 生成一个表A(num int),表A的每个记录中只有一个数字,它是从1到n的随机整数(n是我原始表的大小,大约是4 * 10 ^如上所述8)。
    2. 将表A作为资源文件加载到每个地图,如果现在决定的记录的序号在表A中,则输出此记录,否则丢弃它。
    3. 我认为我的方法不太好,因为如果我想从原始表中采样更多记录,表A将变得非常大并且无法作为资源文件加载。

      那么,任何人都可以给出一个优雅的算法吗?

1 个答案:

答案 0 :(得分:1)

我不确定"优雅"意思是,但也许你对类似于油藏采样的东西感兴趣。设k为样本的大小,并用空值初始化k元素数组。我们抽样的元素一个接一个地到达。当第j个(从1开始计数)元素到达时,我们遍历数组,并且对于每个单元,用当前元素以1 / j的概率独立地替换它的内容。

天真地,运行时间非常糟糕 - 从n中采样k元素,替换成本为O(k n)。但是,对数组的写入次数是期望的O(k log n),因为流中的后续元素很少导致写入。这是一个基于exponential distribution的有效方法(警告:前面轻度测试的Python)。运行时间为O(n + k log n)。

import math
import random


def sample_from(population, k):
    for i, x in enumerate(population):
        if i == 0:
            sample = [x] * k
        else:
            t = float(k) * math.log(1.0 - 1.0 / float(i + 1))
            while True:
                t -= math.log(1.0 - random.random())
                if t >= 0.0:
                    break
                sample[random.randrange(k)] = x
    return sample