在执行时,是否有办法将聚合函数应用于数据框的所有(或列表)列groupBy
?换句话说,有一种方法可以避免对每一列都这样做:
df.groupBy("col1")
.agg(sum("col2").alias("col2"), sum("col3").alias("col3"), ...)
Answers:
有多种将聚合函数应用于多个列的方法。
GroupedData
类提供了许多方法用于最常见的功能,包括count
,max
,min
,mean
和sum
,其可以直接使用,如下所示:
蟒蛇:
df = sqlContext.createDataFrame(
[(1.0, 0.3, 1.0), (1.0, 0.5, 0.0), (-1.0, 0.6, 0.5), (-1.0, 5.6, 0.2)],
("col1", "col2", "col3"))
df.groupBy("col1").sum()
## +----+---------+-----------------+---------+
## |col1|sum(col1)| sum(col2)|sum(col3)|
## +----+---------+-----------------+---------+
## | 1.0| 2.0| 0.8| 1.0|
## |-1.0| -2.0|6.199999999999999| 0.7|
## +----+---------+-----------------+---------+
斯卡拉
val df = sc.parallelize(Seq(
(1.0, 0.3, 1.0), (1.0, 0.5, 0.0),
(-1.0, 0.6, 0.5), (-1.0, 5.6, 0.2))
).toDF("col1", "col2", "col3")
df.groupBy($"col1").min().show
// +----+---------+---------+---------+
// |col1|min(col1)|min(col2)|min(col3)|
// +----+---------+---------+---------+
// | 1.0| 1.0| 0.3| 0.0|
// |-1.0| -1.0| 0.6| 0.2|
// +----+---------+---------+---------+
(可选)您可以传递应汇总的列的列表
df.groupBy("col1").sum("col2", "col3")
您还可以通过字典/映射通过列a作为关键字和功能作为值:
蟒蛇
exprs = {x: "sum" for x in df.columns}
df.groupBy("col1").agg(exprs).show()
## +----+---------+
## |col1|avg(col3)|
## +----+---------+
## | 1.0| 0.5|
## |-1.0| 0.35|
## +----+---------+
斯卡拉
val exprs = df.columns.map((_ -> "mean")).toMap
df.groupBy($"col1").agg(exprs).show()
// +----+---------+------------------+---------+
// |col1|avg(col1)| avg(col2)|avg(col3)|
// +----+---------+------------------+---------+
// | 1.0| 1.0| 0.4| 0.5|
// |-1.0| -1.0|3.0999999999999996| 0.35|
// +----+---------+------------------+---------+
最后,您可以使用varargs:
蟒蛇
from pyspark.sql.functions import min
exprs = [min(x) for x in df.columns]
df.groupBy("col1").agg(*exprs).show()
斯卡拉
import org.apache.spark.sql.functions.sum
val exprs = df.columns.map(sum(_))
df.groupBy($"col1").agg(exprs.head, exprs.tail: _*)
还有其他一些方法可以达到类似的效果,但是在大多数情况下,这些方法应该绰绰有余。
也可以看看:
Dataset.groupBy
/ Dataset.groupByKey
和RDD.groupBy
/RDD.groupByKey
在一般情况下具有不同的语义。如果是简单DataFrame
聚合,请检查此。还有更多,但在这里并不重要。
exprs = [min(x).alias("{0}".format(x)) for x in df.columns]
相同概念的另一个示例-但说-您有2个不同的列-您想对每个应用不同的agg函数,即
f.groupBy("col1").agg(sum("col2").alias("col2"), avg("col3").alias("col3"), ...)
这是实现它的方法-尽管在这种情况下我还不知道如何添加别名
请参见下面的示例-使用地图
val Claim1 = StructType(Seq(StructField("pid", StringType, true),StructField("diag1", StringType, true),StructField("diag2", StringType, true), StructField("allowed", IntegerType, true), StructField("allowed1", IntegerType, true)))
val claimsData1 = Seq(("PID1", "diag1", "diag2", 100, 200), ("PID1", "diag2", "diag3", 300, 600), ("PID1", "diag1", "diag5", 340, 680), ("PID2", "diag3", "diag4", 245, 490), ("PID2", "diag2", "diag1", 124, 248))
val claimRDD1 = sc.parallelize(claimsData1)
val claimRDDRow1 = claimRDD1.map(p => Row(p._1, p._2, p._3, p._4, p._5))
val claimRDD2DF1 = sqlContext.createDataFrame(claimRDDRow1, Claim1)
val l = List("allowed", "allowed1")
val exprs = l.map((_ -> "sum")).toMap
claimRDD2DF1.groupBy("pid").agg(exprs) show false
val exprs = Map("allowed" -> "sum", "allowed1" -> "avg")
claimRDD2DF1.groupBy("pid").agg(exprs) show false
当前答案在如何创建聚合上是完全正确的,但是没有一个能真正解决问题中也要求的列别名/重命名。
通常,这是我处理这种情况的方式:
val dimensionFields = List("col1")
val metrics = List("col2", "col3", "col4")
val columnOfInterests = dimensions ++ metrics
val df = spark.read.table("some_table").
.select(columnOfInterests.map(c => col(c)):_*)
.groupBy(dimensions.map(d => col(d)): _*)
.agg(metrics.map( m => m -> "sum").toMap)
.toDF(columnOfInterests:_*) // that's the interesting part
最后一行从本质上将聚合数据帧的每一列重命名为原始字段,本质上进行了更改,sum(col2)
并sum(col3)
简单地更改为col2
和col3
。
aggregateBy
在这里适用。它比快(快得多)groupBy
。哦,等等-DataFrame
不暴露aggregateBy
-agg
指向groupBy
。好吧,这意味着DataFrames
很慢..