Applying an operation (whose result depends on the information in the entire DataFrame) on certain rows of the DataFrame in PySpark
我目前正在努力实施Spark-y方法来使用PySpark进行操作。我有一个具有以下结构的大型DataFrame(约500,000行)
1 2 3 4 5 6 7 | ID DATE CHANGE POOL ----------------------------- 1 ID1 DATE1 CHANGE1 POOL1 2 ID2 DATE2 CHANGE2 POOL2 3 ID3 DATE3 CHANGE3 POOL3 4 ID4 DATE4 CHANGE4 POOL4 .... |
其中
排序
我想通过以下操作替换
我试图通过窗口函数来(部分)实现这一点,如下所示(我可以用
1 2 3 4 5 6 7 | POOL_DAYS = 180 days = lambda i: i * 86400 window_glb = Window\\ .partitionBy()\\ .orderBy(col('DATE').cast('long'))\\ .rangeBetween(-days(POOL_DAYS), 0) df = df.withColumn('POOL', collect_list('CHANGE').over(window_glb)) |
但由于此错误而崩溃
1 2 3 | Py4JJavaError: An error occurred while calling o1859.collectToPython. : org.apache.spark.SparkException: Job aborted due to stage failure: Task 0 in stage 203.1 failed 4 times, most recent failure: Lost task 0.3 in stage 203.1 (TID 6339, xxxxxxxxxx.com, executor 1): java.lang.IllegalArgumentException: Size exceeds Integer.MAX_VALUE |
在我看来,这似乎是内存不足的问题。为了对此进行测试,我对原始DataFrame的一个较小子集使用了相同的操作,并成功完成了该操作。
请注意,我确实了解到上述实现对所有行都重复了该操作,而没有考虑
蛮力(而不是完全使用Spark-y)方法是对具有空 但是,预计需要很长时间才能完成。 更新:我也尝试过使用UDF 但是由于函数的结果取决于整个(或大部分)DataFrame上的信息,因此它会因错误而停止 第一个基于窗口函数的方法,蛮力方法和损坏的UDF的尝试,我该如何实现?我需要能够对从感兴趣的日期起某个日期范围内的DataFrame的子集进行分组和处理;如何使用Spark进行此操作? 我对Spark(和PySpark)非常陌生,并且很难思考这个问题。我非常感谢您的帮助。谢谢! 我正在回答我自己的问题:我选择 现在,DataFrame
2
3
4
5
6
end_date = row.DATE
start_date = end_date - datetime.timedelta(days = window_size)
return df.where((col('DATE') < end_date) & (col('DATE') >= start_date))\\
.agg(collect_list('CHANGE'))\\
.rdd.flatMap(list).first()
2
3
4
5
6
7
end_date = date
start_date = end_date - datetime.timedelta(days = window_size)
return df.where((col('DATE') < end_date) & (col('DATE') >= start_date))\\
.agg(collect_list('CHANGE'))\\
.rdd.collect()
get_pool_udf = udf(get_pool, ArrayType(DoubleType()))
2
py4j.Py4JException: Method __getnewargs__([]) does not exist
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.withColumnRenamed('DATE', 'r_DATE')\\
.withColumnRenamed('CHANGE', 'r_CHANGE')
no_pool_df = df.where(size('POOL') == 0)
cross_df = no_pool_df\\
.join(renamed_df,\\
(renamed_df.r_DATE >= date_sub(no_pool_df.DATE, POOL_DAYS)) &\\
(renamed_df.r_DATE < no_pool_df.DATE)\\
, 'right')\\
.select('ID', 'r_CHANGE')\\
.groupBy('ID')\\
.agg(collect_list('r_CHANGE'))\\
.withColumnRenamed('ID', 'no_pool__ID')\\
.withColumnRenamed('collect_list(r_CHANGE)', 'no_pool__POOL')
df = df.join(cross_df, cross_df.no_pool__ID == df.ID, 'left_outer')\\
.drop('no_pool__ID')
2
3
4
5
6
7
8
9
if not history:
return no_history
else:
return history
mix_pools_udf = sfn.udf(mix_pools, ArrayType(DoubleType()))
df = df.withColumn('POOL_mix', mix_pools_udf(col('POOL'), col('no_pool__POOL')))\\
.drop('POOL', 'no_pool__POOL')