Spark SQL:对列列表应用聚合函数

xdnvmnnf  于 2022-12-23  发布在  Apache
关注(0)|答案(4)|浏览(93)

在执行groupBy时,是否有办法将聚合函数应用于 Dataframe 的所有列(或列列表)?换句话说,是否有办法避免对每列都执行此操作:

df.groupBy("col1")
  .agg(sum("col2").alias("col2"), sum("col3").alias("col3"), ...)
t1rydlwq

t1rydlwq1#

将聚合函数应用于多个列的方法有多种。
GroupedData类为最常用的函数提供了很多方法,包括countmaxminmeansum,可以直接使用如下:

  • 巨蟒:
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")

您还可以将dictionary/map的列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: _*)

还有一些其他的方法来达到类似的效果,但这些应该绰绰有余的大部分时间。
另见:

jrcvhitl

jrcvhitl2#

这是同一概念的另一个示例,假设您有2个不同的列,并且您希望对每个列应用不同的agg函数,即

f.groupBy("col1").agg(sum("col2").alias("col2"), avg("col3").alias("col3"), ...)

下面是实现它的方法-尽管我还不知道如何在这种情况下添加别名
请参阅以下示例-使用Map

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
ekqde3dh

ekqde3dh3#

当前的答案在如何创建聚合方面是完全正确的,但是没有一个答案实际上解决了问题中也要求的列别名/重命名问题。
通常,我是这样处理这种情况的:

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

最后一行实际上将聚合 Dataframe 的每一列重命名为原始字段,实际上将sum(col2)sum(col3)简单地更改为col2col3

btqmn9zl

btqmn9zl4#

对于pyspark,你可以使用下面的,它可以合并不同的列名和聚合函数,威尔斯重命名。

from pyspark.sql.functions import expr
dims = ["col1"]
mertrics = ["col2", "col3", "col4"]
aggFuncs = ["sum", "avg", "max"]

aggs = [expr(f"{a}({c}) as {c}_{a}") for c in metrics for a in aggFuncs]
# or you can also do below, they are equivalent
# aggs = [expr(f"{a}({c})").alias(f"{c}_{a}") for c in metrics for a in aggFuncs]

df.groupBy(*dims).agg(*aggs).show()

相关问题