簡體   English   中英

pyspark 內存高效循環將指標列添加到 dataframe

[英]pyspark memory-efficient loop to add indicator columns to dataframe

有沒有辦法將以下代碼轉換為利用for循環中的 pyspark 並行化的代碼?

import pyspark.sql.functions as F

my_list_of_integers = list(df_column_of_integers.select('column_name').toPandas()['column_name'])

for my_int in my_list_of_integers:    
    temp_df = large_df1.filter(large_df1.a_value_column == my_int)
    temp_df = temp_df.select("a_key_column")
    temp_df = temp_df.withColumn("indicator" + str(my_int), F.lit(1))
    large_df2 = large_df2.join(temp_df, on="a_key_column", how="left")

經過 7 次for循環(目標是 185)后,代碼失敗並給出以下錯誤消息:

org.apache.spark.memory.SparkOutOfMemoryError: Unable to acquire 52 bytes of memory, got 0

我正在使用的系統報告的另一條錯誤消息建議如何解決該問題:

您的作業已超出 memory 開銷。 您的代碼可能試圖完全在一個執行器上運行,如果您沒有使用 pySpark,就會發生這種情況; 例如,如果您使用的是 Pandas 或 UDF。

對於一個簡單的工作示例,這里是示例輸入和來自此示例輸入的預期 output 的可視化:

樣本輸入:

df_column_of_integers = spark.createDataFrame([10, 11, 13], IntegerType()).toDF('column_name')

df1_key_column = [52, 52, 53, 53, 52, 52]
a_value_column = [9, 13, 10, 11, 12, 10]
large_df1 = sqlContext.createDataFrame(zip(df1_key_column, a_value_column), schema=['a_key_column', 'a_value_column'])

large_df2 = spark.createDataFrame([52, 54, 53], IntegerType()).toDF('a_key_column')

預期的 output(即上面簡單示例的 large_df2 的最終版本):

+--------------+-------------+-------------+-------------+                                                              
|  a_key_column|  indicator10|  indicator11|  indicator13|
+--------------+-------------+-------------+-------------+
|            52|            1|         NULL|            1|
|            54|         NULL|         NULL|         NULL|
|            53|            1|            1|         NULL|
+--------------+-------------+-------------+-------------+

實際上,我的 df_column_of_integers 有 185 個條目。 large_df1 在for循環的第一步被過濾之前有 8200 萬行和 2 列,在該過濾器之后最多有 90 萬行。 large_df2 以 90 萬行和 33 列開始(其中 23 個是整數)。 從詳細的錯誤消息來看,似乎是在加入期間發生了錯誤。 但是,我過去在這個系統上加入了更大的數據集,而不是在 Pandas 列表上的for循環中,所以它讓我認為問題的根源是使用了 Pandas 列表,它提示使用單個執行程序。 因此,我認為可能會有更好的循環技術,有人可能知道。

I tried using.foreach with a lambda function, as described here: https://sparkbyexamples.com/pyspark/pyspark-loop-iterate-through-rows-in-dataframe/ , but I cannot figure out how to add large_df1 and large_df2作為 lambda function 的附加輸入。 而且我不認為。map 會有所幫助,因為我不想編輯 my_list_of_integers,只想對其值進行交互。

先感謝您!

我解決了我的問題:我將for循環中的所有內容替換為:

import pyspark.sql.functions as F

large_df1 = large_df1.filter(large_df1.a_value_column.isin(my_list_of_integers))
large_df1 = large_df1.withColumn("my_value". F.lit(1))
large_df1 = large_df1.groupBy("a_key_column").pivot("a_value_column", my_list_of_integers).agg(F.first(F.col("my_value")))
large_df2 = large_df2.join(large_df1, on="a_key_column", how="left")

關鍵步驟是使用pivot 新代碼運行方便快捷。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM