我的数据如下:
id | duration | action1 | action2 | ...
---------------------------------------------
1 | 10 | A | D
1 | 10 | B | E
2 | 25 | A | E
1 | 7 | A | G
我想按ID分组(效果很好!):
df.rdd.groupBy(lambda x: x['id']).mapValues(list).collect()
现在我想按持续时间对每组中的值进行分组,得到类似的结果:
[(id=1,
((duration=10,[(action1=A,action2=D),(action1=B,action2=E),
(duration=7,(action1=A,action2=G)),
(id=2,
((duration=25,(action1=A,action2=E)))]
这里是我不知道如何做嵌套组的地方。有什么提示吗?
答案 0 :(得分:3)
无需序列化为rdd
。以下是按多列分组并将其余列聚合到列表中而不对所有列进行硬编码的通用方法:
from pyspark.sql.functions import collect_list
grouping_cols = ["id", "duration"]
other_cols = [c for c in df.columns if c not in grouping_cols]
df.groupBy(grouping_cols).agg(*[collect_list(c).alias(c) for c in other_cols]).show()
#+---+--------+-------+-------+
#| id|duration|action1|action2|
#+---+--------+-------+-------+
#| 1| 10| [A, B]| [D, E]|
#| 2| 25| [A]| [E]|
#| 1| 7| [A]| [G]|
#+---+--------+-------+-------+
<强>更新强>
如果您需要preserve the order这些操作,最好的方法是使用pyspark.sql.Window
和orderBy()
。这是因为groupBy()
跟orderBy()
maintains that order之后"ts"
是否存在歧义。
假设您的时间戳存储在from pyspark.sql import Window
w = Window.partitionBy(grouping_cols).orderBy("ts")
grouped_df = df.select(
*(grouping_cols + [collect_list(c).over(w).alias(c) for c in other_cols])
).distinct()
列中。您应该能够执行以下操作:
df