如何对数据框的行进行分组(在Scala中),如何求和该行的列的值?

时间:2019-07-03 13:14:40

标签: scala apache-spark

我有一个这样的数据框:

ev1    ev2    Score    seconds
A      A       9        0
B      E       1        0
C      C       6        8
D      B       3        10
E      D       5        0
A      E       8        0
C      F       6        0
E      C       3        0
F      B       6        11
D      B       7        0
A      B       9        0
D      G       8        0
G      A       6        9
...    ...     ...      ...

我想对行进行分组,直到“ seconds”的值在9到11之间,并且我想对这些行的“ Score”值求和。

在输出中,我应该是这样的:

group    sum
   1     19
   2     28
   3     30
   ...    ...

第一个分区包含得分为(9 1 6 3)的行,而“和”(19)是这些值的总和,第二个分区包含(5 8 6 3 6),依此类推。

1 个答案:

答案 0 :(得分:2)

您可以在此处使用窗口功能来定义组。

要定义它是否为新组,我们需要检查seconds的先前值是否在9到11之间。

// Some useful imports
import org.apache.spark.sql.{functions => F}
import org.apache.spark.sql.expressions.Window

// Your data with an order defined by monotanically_increasing_id as you are reading it, before any shuffle.
val df = Seq(
("A", "A", 9, 0),
("B", "E", 1, 0),
("C", "C", 6, 8),
("D", "B", 3, 10),
("E", "D", 5, 0),
("A", "E", 8, 0),
("C", "F", 6, 0),
("E", "C", 3, 0),
("F", "B", 6, 11),
("D", "B", 7, 0),
("A", "B", 9, 0),
("D", "G", 8, 0),
("G", "A", 6, 9)
).toDF("ev1", "ev2", "Score", "seconds").withColumn("time_col", F.monotonically_increasing_id)

// Here we are defining the groupId using Window function

val groupIdWindow = Window.orderBy("time_col")

val df2 = df.
withColumn("lagged_seconds", F.lag('seconds, 1, 0) over groupIdWindow).
withColumn("newGroup", ('lagged_seconds > 8 && 'lagged_seconds < 12).cast("bigint")).
withColumn("groupId", sum("newGroup").over(groupIdWindow) + 1)

df2.show
/*

+---+---+-----+-------+--------+--------------+--------+-------+
|ev1|ev2|Score|seconds|time_col|lagged_seconds|newGroup|groupId|
+---+---+-----+-------+--------+--------------+--------+-------+
|  A|  A|    9|      0|       0|             0|       0|      1|
|  B|  E|    1|      0|       1|             0|       0|      1|
|  C|  C|    6|      8|       2|             0|       0|      1|
|  D|  B|    3|     10|       3|             8|       0|      1|
|  E|  D|    5|      0|       4|            10|       1|      2|
|  A|  E|    8|      0|       5|             0|       0|      2|
|  C|  F|    6|      0|       6|             0|       0|      2|
|  E|  C|    3|      0|       7|             0|       0|      2|
|  F|  B|    6|     11|       8|             0|       0|      2|
|  D|  B|    7|      0|       9|            11|       1|      3|
|  A|  B|    9|      0|      10|             0|       0|      3|
|  D|  G|    8|      0|      11|             0|       0|      3|
|  G|  A|    6|      9|      12|             0|       0|      3|
+---+---+-----+-------+--------+--------------+--------+-------+

*/

// And now, a simple groupBy

df2.groupBy("groupId").agg(F.sum("Score").as("Score")).show
/*
-------+-----+
|groupId|Score|
+-------+-----+
|      1|   19|
|      2|   28|
|      3|   30|
+-------+-----+
*/