【问题标题】:Applying aggregate function to every column of certain type将聚合函数应用于特定类型的每一列
【发布时间】:2015-12-05 22:31:47
【问题描述】:

所以我写了关于如何平均我的数据框中的每个 FloatType 列的基础(不起作用),如下所示:

val descript = df.dtypes

  var decimalArr = new ListBuffer[String]()
  for(i <- 0 to (descript.length - 1)) {
    if(descript(i)._2 == "FloatType") {
      decimalArr += descript(i)._1
    }
  }

  //Build Statsitical Arguments for DataFrame Pass
  var averageList = new ListBuffer[String]()
  for(i <- 0 to (decimalArr.length - 1)){
    averageList += "avg(" + '"' + decimalArr(i) + '"' + ")"
  }

  //sample statsitical call
  val sampAvg = df.agg(averageList).show 

averageList生成的例子是:

ListBuffer(avg("offer_id"), avg("decision_id"), avg("offer_type_cd"), avg("promo_id"), avg("pymt_method_type_cd"), avg("cs_result_id"), avg("cs_result_usage_type_cd"), avg("rate_index_type_cd"), avg("sub_product_id"))

明显的问题是 val sampAvg = df.agg(averageList).show 不允许 listBuffer 作为输入。因此,即使将它带入 .toString 也行不通,它需要 org.apache.spark.sql.Column*。有谁知道我可以按照我正在尝试的方式做某事的方法。

旁注我使用的是 Spark 1.3

【问题讨论】:

  • 你试过 sc.parallelize on averageList 然后 .toDF() 函数吗?

标签: scala apache-spark apache-spark-sql


【解决方案1】:

你可以先建立一个聚合表达式列表

import org.apache.spark.sql.functions.{col, avg, lit}

val exprs = df.dtypes
  .filter(_._2 == "DoubleType")
  .map(ct => avg(col(ct._1))).toList

和任一模式匹配

exprs match {
  case h::t => df.agg(h, t:_*)
  case _ => sqlContext.emptyDataFrame
}

或使用虚拟列

df.agg(lit(1).alias("_dummy"), exprs: _*).drop("_dummy")

如果你想使用多个函数,你可以明确地flatMap

import org.apache.spark.sql.Column
import org.apache.spark.sql.functions.{avg, min, max}

val funs: List[(String => Column)] = List(min, max, avg)

val exprs: Array[Column] = df.dtypes 
   .filter(_._2 == "DoubleType")
   .flatMap(ct => funs.map(fun => fun(ct._1)))

或用于理解:

val exprs: Array[Column] = for {
    cname <-  df.dtypes.filter(_._2 == "DoubleType").map(_._1)
    fun <- funs
} yield fun(cname)

如果您想使用模式匹配方法,请将exprs 转换为List

【讨论】:

  • 质疑为什么 val exprs = df.dtypes .filter(._2 == "DoubleType") .map(ct => avg(col(ct._1))).toList 工作但如果我把它分解 val exprs = df.dtypes.filter(._2 == "DoubleType") 和 val avg = exprs.map(ct => avg(col(ct._1))).toList不会吗?我也计划做 min 和 max,所以如果有意义的话,我想拆分映射并组合成一个大型聚合。
  • 因为如果你使用 val avg = exprs.map(ct =&gt; avg(col(ct._1))).toList 你会得到一个递归调用(注意 LHS 和 RHS 上的 avg)并且它会很长时间地混淆编译器。
  • @zero323 感谢您提供如此详细的解释。有什么方法可以对所有数字列应用聚合,例如IntegerTypeDoubletype
  • @agnes 在 Scala 中?除了枚举?不是我知道的。分数和整数类型没有共同的层次结构,基础对象是私有的。
  • @zero323 是在 scala 中。因为让我们说一下我自动化和自定义describe() 以计算数据帧所有列的统计信息的方式,无论是字符串还是数字。如果会有一个层次结构,我可以在所有numeric 列上一起做agg。相反,现在我必须对所有其他 sql 数据类型进行硬编码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-24
  • 2021-04-25
  • 1970-01-01
  • 2020-12-14
  • 2021-04-09
  • 2016-02-26
  • 1970-01-01
相关资源
最近更新 更多