对Dataframe中所有行的列值求和 - scala / spark

时间:2017-10-28 18:01:29

标签: scala apache-spark dataframe

我是scala / spark的新手。我正在使用spark上的scala / java应用程序,尝试从hive表中读取一些数据,然后总结每行的所有列值。例如,考虑以下DF:

+--------+-+-+-+-+-+-+
| address|a|b|c|d|e|f|
+--------+-+-+-+-+-+-+
|Newyork |1|0|1|0|1|1|
|   LA   |0|1|1|1|0|1|
|Chicago |1|1|0|0|1|1|
+--------+-+-+-+-+-+-+

我想总结所有行中的所有1并得到total.i.e。上面的数据帧的所有列的总和应该是12(因为在所有行中有12个1的组合)

我试过这样做:

var count = 0
DF.foreach( x => {
    count = count + Integer.parseInt(x.getAs[String]("a")) + Integer.parseInt(x.getAs[String]("b")) + Integer.parseInt(x.getAs[String]("c")) + Integer.parseInt(x.getAs[String]("d")) + Integer.parseInt(x.getAs[String]("e")) + Integer.parseInt(x.getAs[String]("f")) 
})

运行上述代码时,count值仍为zero。我认为这与在群集上运行应用程序有关。因此,声明一个变量并添加它对我来说不起作用,因为我必须在一个集群上运行我的应用程序。我也尝试在一个单独的java类中声明静态变量并添加它 - 这给了我相同的结果。

据我所知,应该有一种简单的方法可以使用spark / scala库中提供的内联函数来实现这一点。

实现这一目标的有效方法是什么?任何帮助将不胜感激。

谢谢。

P.S:我正在使用Spark 1.6。

2 个答案:

答案 0 :(得分:1)

您可以先对列值求和,然后返回sum s的单行数据帧,然后将此行转换为Seq并将值相加:

val sum_cols = df.columns.tail.map(x => sum(col(x)))    
df.agg(sum_cols.head, sum_cols.tail: _*).first.toSeq.asInstanceOf[Seq[Long]].sum
// res9: Long = 12
df.agg(sum_cols.head, sum_cols.tail: _*).show
+------+------+------+------+------+------+
|sum(a)|sum(b)|sum(c)|sum(d)|sum(e)|sum(f)|
+------+------+------+------+------+------+
|     2|     2|     2|     1|     2|     3|
+------+------+------+------+------+------+

答案 1 :(得分:0)

这是另一种方法:

首先让我们准备一个聚合函数:

scala> val f = df.drop("address").columns.map(col).reduce((c1, c2) => c1 + c2)
f: org.apache.spark.sql.Column = (((((a + b) + c) + d) + e) + f)

将sum作为DataFrame获取:

scala> df.agg(sum(f).alias("total")).show
+-----+
|total|
+-----+
|   12|
+-----+

将总和作为Long数字:

scala> df.agg(sum(f)).first.getLong(0)
res39: Long = 12