如何合并pyspark中的行?
在PySpark中,有一个如何合并pyspark中的行?,pyspark,Pyspark,在PySpark中,有一个coalesce(colA,colB,…)的概念,它每行从这些列中获取它遇到的第一个非空值。但是,我希望合并(rowA,rowB,…)即,每列能够从这些行中获取它遇到的第一个非空值。我想合并一组行或行窗口中的所有行 例如,给定以下数据集,我希望按类别合并行,并按日期升序排列 我应该得到的输出是 +---------+-----------+------+------+ | category| date| val1| val2| +---------+--
coalesce(colA,colB,…)
的概念,它每行从这些列中获取它遇到的第一个非空值。但是,我希望合并(rowA,rowB,…)
即,每列能够从这些行中获取它遇到的第一个非空值。我想合并一组行或行窗口中的所有行
例如,给定以下数据集,我希望按类别合并行,并按日期升序排列
我应该得到的输出是
+---------+-----------+------+------+
| category| date| val1| val2|
+---------+-----------+------+------+
| A| 2020-05-01| 2| 1|
| B| 2020-05-01| 4| null|
| C| 2020-05-01| 5| 2|
| D| 2020-05-01| null| 4|
+---------+-----------+------+------+
首先,我会给出答案。然后,我将指出重要的部分
from pyspark.sql import Window
from pyspark.sql.functions import col, dense_rank, first
df = ... # dataframe from question description
window = (
Window
.partitionBy("category")
.orderBy(col("date").asc())
)
window_unbounded = (
window
.rangeBetween(Window.unboundedPreceding, Window.unboundedFollowing)
)
cols_to_merge = [col for col in df.columns if col not in ["category", "date"]]
merged_cols = [first(col, True).over(window_unbounded).alias(col) for col in cols_to_merge]
df_merged = (
df
.select([col("category"), col("date")] + merged_cols)
.withColumn("rank_col", dense_rank().over(window))
.filter(col("rank_col") == 1)
.drop("rank_col")
)
合并的行方式类似于聚合函数。具体来说,我们将first与ignorenulls=True一起使用,以便找到第一个非null值
当我们使用first时,我们必须注意它应用到的行的顺序。因为,我们用的是一个
窗口本身在两端必须是无界的,而不是默认值,否则我们将在组的子集上运行first
聚合
在对窗口进行聚合后,我们将列重新命名为其原始名称,以保持列名的一致性
我们使用cols的单个select语句,而不是带有df.withColumn(col,…)
的for循环,因为select语句大大降低了查询计划的深度。如果使用looped withColumn,如果列太多,可能会出现堆栈溢出错误
最后,我们在窗口上运行一个densite_-rank
——这次使用默认范围的窗口——并只筛选排名第一的行。我们在这里使用密集排名,但我们可以使用任何排名函数,任何适合我们需要的函数
from pyspark.sql import Window
from pyspark.sql.functions import col, dense_rank, first
df = ... # dataframe from question description
window = (
Window
.partitionBy("category")
.orderBy(col("date").asc())
)
window_unbounded = (
window
.rangeBetween(Window.unboundedPreceding, Window.unboundedFollowing)
)
cols_to_merge = [col for col in df.columns if col not in ["category", "date"]]
merged_cols = [first(col, True).over(window_unbounded).alias(col) for col in cols_to_merge]
df_merged = (
df
.select([col("category"), col("date")] + merged_cols)
.withColumn("rank_col", dense_rank().over(window))
.filter(col("rank_col") == 1)
.drop("rank_col")
)