繁体   English   中英

使用 pyspark/spark 对大型分布式数据集进行采样

[英]Sampling a large distributed data set using pyspark / spark

我在 hdfs 中有一个文件,它分布在集群中的节点上。

我正在尝试从此文件中获取 10 行的随机样本。

在 pyspark shell 中,我使用以下命令将文件读入 RDD:

>>> textFile = sc.textFile("/user/data/myfiles/*")

然后我想简单地做一个样本......关于 Spark 很酷的事情是有像takeSample这样的命令,不幸的是我认为我做错了什么,因为以下需要很长时间:

>>> textFile.takeSample(False, 10, 12345)

所以我尝试在每个节点上创建一个分区,然后使用以下命令指示每个节点对该分区进行采样:

>>> textFile.partitionBy(4).mapPartitions(lambda blockOfLines: blockOfLines.takeSample(False, 10, 1234)).first()

但这会产生错误ValueError: too many values to unpack

org.apache.spark.api.python.PythonException: Traceback (most recent call last):
  File "/opt/cloudera/parcels/CDH-5.0.2-1.cdh5.0.2.p0.13/lib/spark/python/pyspark/worker.py", line 77, in main
    serializer.dump_stream(func(split_index, iterator), outfile)
  File "/opt/cloudera/parcels/CDH-5.0.2-1.cdh5.0.2.p0.13/lib/spark/python/pyspark/serializers.py", line 117, in dump_stream
    for obj in iterator:
  File "/opt/cloudera/parcels/CDH-5.0.2-1.cdh5.0.2.p0.13/lib/spark/python/pyspark/rdd.py", line 821, in add_shuffle_key
    for (k, v) in iterator:
ValueError: too many values to unpack

如何使用 spark 或 pyspark 从大型分布式数据集中采样 10 行?

尝试使用textFile.sample(false,fraction,seed)代替。 takeSample通常会很慢,因为它在 RDD 上调用count() 它需要这样做,因为否则它不会从每个分区中均匀获取,基本上它使用计数以及您要求的样本大小来计算分数并在内部调用sample sample很快,因为它只使用一个随机布尔生成器,该生成器在时间的百分比中返回真实的fraction ,因此不需要调用count

此外,我认为这不会发生在你身上,但如果返回的样本量不够大,它会再次调用sample ,这显然会减慢它的速度。 由于您应该对数据的大小有所了解,因此我建议您调用 sample,然后自己将样本缩小到大小,因为您对数据的了解比 spark 多。

使用 sample 而不是 takeSample 似乎可以让事情变得相当快:

textFile.sample(False, .0001, 12345)

这样做的问题是,除非您对数据集中的行数有一个大致的了解,否则很难知道要选择的正确分数。

PySpark 中不同类型的样本

随机抽样 % 有替换和无替换的数据

import pyspark.sql.functions as F
#Randomly sample 50% of the data without replacement
sample1 = df.sample(False, 0.5, seed=0)

#Randomly sample 50% of the data with replacement
sample1 = df.sample(True, 0.5, seed=0)

#Take another sample exlcuding records from previous sample using Anti Join
sample2 = df.join(sample1, on='ID', how='left_anti').sample(False, 0.5, seed=0)

#Take another sample exlcuding records from previous sample using Where
sample1_ids = [row['ID'] for row in sample1.ID]
sample2 = df.where(~F.col('ID').isin(sample1_ids)).sample(False, 0.5, seed=0)

#Generate a startfied sample of the data across column(s)
#Sampling is probabilistic and thus cannot guarantee an exact number of rows
fractions = {
        'NJ': 0.5, #Take about 50% of records where state = NJ
    'NY': 0.25, #Take about 25% of records where state = NY
    'VA': 0.1, #Take about 10% of records where state = VA
}
stratified_sample = df.sampleBy(F.col('state'), fractions, seed=0)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM