火花RDD中的选择性采样

时间:2015-12-09 15:59:27

标签: scala apache-spark pyspark

我有来自已记录事件的RDD我想要为每个类别提取少量样本。

数据如下所示

|xxx|xxxx|xxxx|type1|xxxx|xxxx
|xxx|xxxx|xxxx|type2|xxxx|xxxx|xxxx|xxxx
|xxx|xxxx|xxxx|type3|xxxx|xxxx|xxxx
|xxx|xxxx|xxxx|type3|xxxx|xxxx|xxxx
|xxx|xxxx|xxxx|type4|xxxx|xxxx|xxxx|xxxx|xxxx
|xxx|xxxx|xxxx|type1|xxxx|xxxx
|xxx|xxxx|xxxx|type6|xxxx

我的尝试

eventlist = ['type1', 'type2'....]
orginalRDD = sc.textfile("/path/to/file/*.gz").map(lambda x: x.split("|"))

samplelist = []
for event in event list:
    eventsample = orginalRDD.filter(lambda x: x[3] == event).take(5).collect()
    samplelist.extend(eventsample)

print samplelist

我对此有两个问题,
    1.根据具体情况收集样品的一些更好的方法/有效方法?
    2.是否可以收集非分裂线而不是分割线?

欢迎使用Python或scala建议!

1 个答案:

答案 0 :(得分:1)

如果样本不是随机的,那么这样的事情应该可以正常工作:

n = ...  # Number of elements you want to sample
pairs =  orginalRDD.map(lambda x: (x[3], x))

pairs.aggregateByKey(
    [],  # zero values
    lambda acc, x: (acc + [x])[:n],  # Add new value a trim to n elements
    lambda acc1, acc2: (acc1 + acc2)[:n])  # Combine two accumulators and trim

获取随机样本有点困难。一种可能的方法是在聚合之前添加随机值和排序:

import os
import random

def add_random(iter):
   seed = int(os.urandom(4).encode('hex'), 16)
   rs = random.Random(seed)
   for x in iter:
       yield (rs.random(), x)

(pairs
    .mapPartitions(add_random)
    .sortByKey()
    .values()
    .aggregateByKey(
        [],
        lambda acc, x: (acc + [x])[:n],
        lambda acc1, acc2: (acc1 + acc2)[:n]))

对于DataFrame具体解决方案,请参阅Choosing random items from a Spark GroupedData Object