首页 > 解决方案 > 对 Spark 数据框的列求和并创建另一个数据框

问题描述

我有一个如下所示的数据框 -

在此处输入图像描述

我正在尝试从中创建另一个数据框,它有 2 列 - 列名和每列中的值总和,如下所示 -

在此处输入图像描述

到目前为止,我已经尝试过这个(在 Spark 2.2.0 中)但抛出了一个堆栈跟踪 -

val get_count: (String => Long) = (c: String) => {
    df.groupBy("id")
      .agg(sum(c) as "s")
      .select("s")
      .collect()(0)
      .getLong(0)
}
val sqlfunc = udf(get_count)

summary = summary.withColumn("sum_of_column", sqlfunc(col("c")))

是否有其他替代方法可以完成此任务?

标签: scalaapache-sparkdataframesum

解决方案


我认为最有效的方法是进行聚合,然后构建一个新的数据框。这样你就避免了昂贵的explode.

首先,让我们创建数据框。顺便说一句,当您提出问题时,提供代码来做这件事总是很好的。这样我们可以在几秒钟内重现您的问题。

val df = Seq((1, 1, 0, 0, 1), (1, 1, 5, 0, 0),
             (0, 1, 0, 6, 0), (0, 1, 0, 4, 3))
    .toDF("output_label", "ID", "C1", "C2", "C3")

然后我们构建我们感兴趣的列列表、聚合,并计算结果。

val cols = (1 to 3).map(i => s"C$i")
val aggs = cols.map(name => sum(col(name)).as(name))
val agg_df = df.agg(aggs.head, aggs.tail :_*) // See the note below
agg_df.show
+---+---+---+
| C1| C2| C3|
+---+---+---+
|  5| 10|  4|
+---+---+---+

我们几乎拥有了我们需要的东西,我们只需要收集数据并构建一个新的数据框:

val agg_row = agg_df.first
cols.map(name => name -> agg_row.getAs[Long](name))
    .toDF("column", "sum")
    .show
+------+---+
|column|sum|
+------+---+
|    C1|  5|
|    C2| 10|
|    C3|  4|
+------+---+

编辑:

注意:df.agg(aggs.head, aggs.tail :_*)可能看起来很奇怪。这个想法只是简单地计算在 中计算的所有聚合aggs。人们会期待更简单的东西,例如df.agg(aggs : _*). 然而,该agg方法的签名如下:

def agg(expr: org.apache.spark.sql.Column,exprs: org.apache.spark.sql.Column*)

也许是为了确保至少使用一列,这就是为什么你需要拆分and aggsaggs.headaggs.tail


推荐阅读