Spark SQL:将聚合函数应用于列列表

lil*_*ffa 65 aggregate-functions dataframe apache-spark apache-spark-sql

有没有办法将聚合函数应用于数据帧的所有(或列表)列groupBy?换句话说,有没有办法避免为每一列执行此操作:

df.groupBy("col1")
  .agg(sum("col2").alias("col2"), sum("col3").alias("col3"), ...)
Run Code Online (Sandbox Code Playgroud)

zer*_*323 113

将聚合函数应用于多个列有多种方法.

GroupedData类提供许多用于最常用的功能的方法,包括count,max,min,meansum,其可以直接作为如下使用:

  • 蟒蛇:

    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|
    ## +----+---------+-----------------+---------+
    
    Run Code Online (Sandbox Code Playgroud)
  • 斯卡拉

    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|
    // +----+---------+---------+---------+
    
    Run Code Online (Sandbox Code Playgroud)

您可以选择传递应聚合的列列表

df.groupBy("col1").sum("col2", "col3")
Run Code Online (Sandbox Code Playgroud)

您还可以传递带有列的字典/映射,并将键作为值传递:

  • 蟒蛇

    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|
    ## +----+---------+
    
    Run Code Online (Sandbox Code Playgroud)
  • 斯卡拉

    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|
    // +----+---------+------------------+---------+
    
    Run Code Online (Sandbox Code Playgroud)

最后你可以使用varargs:

还有其他一些方法可以达到类似的效果,但这些方法在大多数情况下应该足够了.

  • 如何为列添加别名? (4认同)
  • @javadba谢谢.这是另一个有用的(主观的,自我推销警报)资源:https://git.io/vM1Ch (3认同)
  • @javadba不,它仅意味着`Dataset.groupBy` /`Dataset.groupByKey`和`RDD.groupBy` /`RDD.groupByKey`在一般情况下具有不同的语义。如果是简单的DataFrame聚合,请[检查此](http://stackoverflow.com/a/32903568/1560062)。还有更多,但在这里并不重要。 (2认同)
  • @GeekFactory`exrs = [min(x).alias("{0}".format(x))for d in df.columns]` (2认同)
  • @zero323 很好的答案。如果我想计算每列的多个统计数据会怎样?会是 **exprs = [ [min(x).alias("{0}_min".format(x)), max(x).alias("{0}_max".format(x)), 意思(x).alias("{0}_mean".format(x)) ] for x in df.columns]** (2认同)

Sum*_*Pal 18

同一概念的另一个例子 - 但是说 - 你有2个不同的列 - 并且你想对它们中的每一个应用不同的agg函数,即

f.groupBy("col1").agg(sum("col2").alias("col2"), avg("col3").alias("col3"), ...)
Run Code Online (Sandbox Code Playgroud)

这是实现它的方法 - 虽然我还不知道如何在这种情况下添加别名

请参阅下面的示例 - 使用地图

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
Run Code Online (Sandbox Code Playgroud)