[英]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.