在时间窗口中聚合

时间:2019-11-15 07:25:37

标签: python pandas pyspark pyspark-sql pyspark-dataframes

我有一个PySpark数据帧(例如df),如下所示:

+-----+-----+----------+-----+
| name| type| timestamp|score|
+-----+-----+----------+-----+
|name1|type1|2012-01-10|   11|
|name1|type1|2012-01-11|   14|
|name1|type1|2012-01-12|    2|
|name1|type3|2012-01-12|    3|
|name1|type3|2012-01-11|   55|
|name1|type1|2012-01-13|   10|
|name1|type2|2012-01-14|   11|
|name1|type2|2012-01-15|   14|
|name2|type2|2012-01-10|    2|
|name2|type2|2012-01-11|    3|
|name2|type2|2012-01-12|   55|
|name2|type1|2012-01-10|   10|
|name2|type1|2012-01-13|   55|
|name2|type1|2012-01-14|   10|
+-----+-----+----------+-----+

在上面的数据框中,对于每个name,我想计算3个连续时间戳中有多少score个值。例如,对于name1,我希望能够检测到score2012-01-10之间有5个2012-01-12值,而{{1}之间有3个分数}到2012-01-13(对于2012-01-15依此类推)。

在我的输出数据框中,我希望行数少于name2中的行数。具体来说,由于我正在对size = 3的窗口进行汇总/计数,因此我希望行数约为〜1/3。我仍然希望有一个timestamp列,它代表窗口的第一个条目。我希望窗户不重叠。

如何使用PySpark做到这一点?

这是我到目前为止尝试过的:

df

但是,当我使用上述技术时,出现以下错误。

win = W.orderBy("timestamp").partitionBy("name").rowsBetween(0,3)
df_agg = df.groupBy( "timestamp" , F.col("name")  ).agg( F.count( F.col("score") ).over(win) )

您可以使用以下代码段创建 org.apache.spark.sql.AnalysisException: expression '`score`' is neither present in the group by, nor is it an aggregate function. (示例数据框)。

df

2 个答案:

答案 0 :(得分:0)

我尝试了以下操作,告诉我这是否是预期的输出:

from pyspark.sql.window import Window

w = Window.partitionBy("name").orderBy("timestamp").rowsBetween(0, 3)
df_agg = demo_df.withColumn("group_count", F.count("score").over(w))
df_agg.show()

# +-----+-----+----------+-----+-----------+
# | name| type| timestamp|score|group_count|
# +-----+-----+----------+-----+-----------+
# |name1|type1|2012-01-10|   11|          4|
# |name1|type1|2012-01-11|   14|          4|
# |name1|type3|2012-01-11|   55|          4|
# |name1|type1|2012-01-12|    2|          4|
# |name1|type3|2012-01-12|    3|          4|
# |name1|type1|2012-01-13|   10|          3|
# |name1|type2|2012-01-14|   11|          2|
# |name1|type2|2012-01-15|   14|          1|
# |name2|type2|2012-01-10|    2|          4|
# |name2|type1|2012-01-10|   10|          4|
# |name2|type2|2012-01-11|    3|          4|
# |name2|type2|2012-01-12|   55|          3|
# |name2|type1|2012-01-13|   55|          2|
# |name2|type1|2012-01-14|   10|          1|
# +-----+-----+----------+-----+-----------+

partitionBy等效于groupBy功能的Window,至少在功能上是明智的。

答案 1 :(得分:0)

一个选项是创建一个数据框,其日期范围从数据框的较低日期开始(可能是2012-01-10)。使用此新数据框对数据框进行内部联接,以获取具有所需日期范围的当前数据,现在您可以使用名称,类型和时间戳进行分组,并使用总和进行汇总。我认为这是最好的选择。您创建的数据框包含日期范围,因此不会花费太多时间。