Apache spark 分组和聚合两次

Apache spark 分组和聚合两次,apache-spark,pyspark,Apache Spark,Pyspark,我有一个如下所示的数据帧: City State Hour Score Percentage DEN CO 1 0 0 DEN CO 1 0 0 DEN CO 2 2 99 DEN CO 3 0 0 NYC NYC 1 0

我有一个如下所示的数据帧:

City     State     Hour   Score     Percentage
DEN      CO        1      0         0
DEN      CO        1      0         0
DEN      CO        2      2         99
DEN      CO        3      0         0
NYC      NYC       1      0         0
City     State     total_hours  total_scores  total_perct.   total_volume      
DEN      CO        [1,2,3]      [0,2,0]       [0,99,0]       [2,1,1]
NYC      NYC       [1]          [0]           [0]            [1]
我希望它看起来像这样:

City     State     Hour   Score     Percentage
DEN      CO        1      0         0
DEN      CO        1      0         0
DEN      CO        2      2         99
DEN      CO        3      0         0
NYC      NYC       1      0         0
City     State     total_hours  total_scores  total_perct.   total_volume      
DEN      CO        [1,2,3]      [0,2,0]       [0,99,0]       [2,1,1]
NYC      NYC       [1]          [0]           [0]            [1]
对于
total_hours
我只是为
City
State
total_scores
做了一个收集每个特定小时的集合,然后收集所有小时的所有分数。例:第一小时的分数是2分,0分和0分,我只取其中一分,然后第二小时的分数是1分,所以它变成了
[0,2]
。与
总销售额相同。
对于
总销售额
,我计算每小时的计数,并收集同一城市和州的所有小时的
列表

这基本上就是我想要实现的。如果我这样做
groupBy

df.groupBy("city", "state", "hour")
  .agg(collect_set("Hour").alias("total_hours"), collect_set("Score").alias("total_scores"), 
       collect_set("Percentage").alias("total_perct."), count("hour").alias("total_volume"))
我将获得以下数据帧:

City     State     total_hours  total_scores  total_perct.   total_volume 
DEN      CO        [1]          [0]           [0]            2
DEN      CO        [2]          [2]           [99]           1
DEN      CO        [3]          [0]           [0]            1
NYC      NYC       [1]          [0]           [0]            1

我不明白从这里该怎么办。我怎样才能得到我现在所拥有的并取得最终的结果?我正在使用PySpark。

Spark<2.4

需要使用
udf
,但在这种情况下速度非常慢:(

Spark 2.4+

好的,这是与
收集集
收集列表
一起使用的

from pyspark.sql.functions import max, count, col, collect_list, flatten

df.groupBy('City', 'State', 'Hour') \
  .agg(collect_set(col('Score')).alias('Score'), collect_set(col('Percentage')).alias('Percentage'), count(col('Hour')).alias('total_volume')) \
  .orderBy('City', 'State', 'Hour') \
  .groupBy('City', 'State') \
  .agg(collect_list(col('Hour')).alias('total_hours'), flatten(collect_list(col('Score'))).alias('total_scores'), flatten(collect_list(col('Percentage'))).alias('total_perct.'), collect_list(col('total_volume')).alias('total_volume')) \
  .show(10, False)

+----+-----+-----------+------------+------------+------------+
|City|State|total_hours|total_scores|total_perct.|total_volume|
+----+-----+-----------+------------+------------+------------+
|NYC |NYC  |[1]        |[0]         |[0]         |[1]         |
|DEN |CO   |[1, 2, 3]  |[0, 2, 0]   |[0, 99, 0]  |[2, 1, 1]   |
+----+-----+-----------+------------+------------+------------+

如果在这一步中没有按排序,则结果列表的顺序将是混合的。

另一种方法是使用窗口计算小时的出现次数,然后根据分区筛选1个索引(idx),然后按groupby+collect\u列表

import pyspark.sql.functions as F
from pyspark.sql.window import Window


输出:

+----+-----+----------+-----------+----------------+------------+
|City|State|total_Hour|total_Score|total_Percentage|total_Volume|
+----+-----+----------+-----------+----------------+------------+
| NYC|  NYC|       [1]|        [0]|             [0]|         [1]|
| DEN|   CO| [1, 2, 3]|  [0, 2, 0]|      [0, 99, 0]|   [2, 1, 1]|
+----+-----+----------+-----------+----------------+------------+

为什么你需要按小时分组?哦,我明白了。有点复杂。@Lamanus我这样做只是为了得到那一小时的总音量,我不确定是否有更好的方法来获得每小时的总音量,然后收集所有小时的所有音量如何合并第一行和第二行?我知道你想得到计数,
2
但是分数和百分比呢?我可以简单地添加分数,但是百分比是多少?其中一个…嗯…@Lamanus我不确定这是否回答了你的问题,但是分数和百分比我们每小时都有一个集合,然后返回并收集所有,例如,如果第1小时的分数为0,1,1,1,2,那么该集合将是[0,1,2]如果第2小时的分数为0,0,0,则结果为[0,1,2,0]百分比也是一样。嗯,你是如何得到扁平化的?在pyspark.sql.functions库中,它说没有名为flatten的函数。我错过了包导入行并添加了。是的,它给了我一个错误,说没有名为flatte的函数:`ImportError:cannot import name'flatte'