我发现了各种类似的问题,但没有一个能回答我的具体问题。
我需要使用基于日期列的最新行值来填充pyspark数据框中的缺失日期行。
我当前的解决方案是计算直到今天为止的缺失日期列表,与原始df合并,并用最新有效值一一填充所有列:
# get the maximum date from the df
max_date = df.select(F.max('date')).first()['max(date)')
today = datetime.date.today()
delta = today - max_date
dates_list = [(today - datetime.timedelta(days=x),) for x in range(delta.days)]
# if there are missing rows
if dates_list:
# create df with one column 'date'
dates_df = spark.createDataFrame(dates_list, schema=date_schema)
# join with original df
df = df.join(F.broadcast(dates_df), ['date'], 'outer')
w = Window.orderBy('date').rangeBetween(Window.unboundedPreceding, 0)
# fill all columns with latest non null col value
for c in df.columns:
if c != 'date':
df = df.withColumn(c, F.last(c, ignorenulls=True).over(w))
此代码的问题在于,原始df包含大量列,并且针对每一个spark计算一个窗口以获取最后的非null值,并且这种方法的效率很低,导致制定了庞大的逻辑计划。 / p>
我想以一种简单的方式来实现它,即简单地获取具有最大日期的行内容(因为它不包含空值),并使用直到今天的计算日期列表来更改日期。
关于如何实施这种方法的任何建议?
示例输入:
date | col_one | col_two | col_three | .. | col_n
-------------------------------------------------------
2020-08-15 | 0.1 | 6.5 | 9.8 | .. | 0.7
2020-08-14 | 0.2 | 5.5 | 1.8 | .. | 3.7
2020-08-13 | 0.4 | 7.5 | 1.3 | .. | 0.5
2020-08-12 | 3.1 | 8.5 | 9.8 | .. | 1.7
2020-08-11 | 0.15 | 6.9 | 9.7 | .. | 0.2
示例输出:
date | col_one | col_two | col_three | .. | col_n
-------------------------------------------------------
2020-08-18 | 0.1 | 6.5 | 9.8 | .. | 0.7
2020-08-17 | 0.1 | 6.5 | 9.8 | .. | 0.7
2020-08-16 | 0.1 | 6.5 | 9.8 | .. | 0.7
2020-08-15 | 0.1 | 6.5 | 9.8 | .. | 0.7
2020-08-14 | 0.2 | 5.5 | 1.8 | .. | 3.7
2020-08-13 | 0.4 | 7.5 | 1.3 | .. | 0.5
2020-08-12 | 3.1 | 8.5 | 9.8 | .. | 1.7
2020-08-11 | 0.15 | 6.9 | 9.7 | .. | 0.2
答案 0 :(得分:0)
一个可能的解决方案是过滤具有最大日期的原始数据框,使用第一个缺少的日期填充日期列,并对每个剩余的缺少的日期将相同的行内容与缺少的日期合并。然后最后使用原始df重新加入:
# compute the list of all dates from maximum date available till today
max_date = df.select(F.max('date')).first()['max(date)']
today = datetime.date.today()
dates_list = [today - datetime.timedelta(days=x) for x in range((today - max_date).days)]
# take the row with latest date values
max_date_values = df.filter(F.col('date') == max_date)
missing_dates_values = None
# duplicate latest values for the dates we are missing till today
for missing_date in dates_list:
if missing_dates_values is None:
missing_dates_values = max_date_values.withColumn('date', F.lit(missing_date))
else:
missing_dates_values = missing_dates_values.unionByName(max_date_values.withColumn('date',
F.lit(missing_date)))
# union with the original df
if dates_list:
df = df.unionByName(missing_dates_values)
在我的用例中,关于火花查询计划,在获得更好的性能之前要简单得多。