web-dev-qa-db-fra.com

Opérations d'agrégation multiples sur la même colonne d'un cadre de données spark

J'ai trois tableaux de type chaîne contenant les informations suivantes:

  • tableau groupBy: contenant les noms des colonnes avec lesquelles je souhaite regrouper mes données.
  • tableau agrégé: contenant les noms des colonnes que je veux agréger.
  • tableau des opérations: contenant les opérations d'agrégation que je veux effectuer

J'essaie d'utiliser des trames de données d'allumage pour y parvenir. Les cadres de données Spark fournissent un agg () où vous pouvez passer une entrée Map [String, String] (avec le nom de la colonne et l'opération d'agrégation respective), mais je souhaite effectuer différentes opérations d'agrégation sur la même colonne de données. Des suggestions sur la façon de réaliser ceci?

19
Richa Banker

Scala :

Vous pouvez par exemple mapper une liste de fonctions avec une mapping définie de nom en fonction:

import org.Apache.spark.sql.functions.{col, min, max, mean}
import org.Apache.spark.sql.Column

val df = Seq((1L, 3.0), (1L, 3.0), (2L, -5.0)).toDF("k", "v")
val mapping: Map[String, Column => Column] = Map(
  "min" -> min, "max" -> max, "mean" -> avg)

val groupBy = Seq("k")
val aggregate = Seq("v")
val operations = Seq("min", "max", "mean")
val exprs = aggregate.flatMap(c => operations .map(f => mapping(f)(col(c))))

df.groupBy(groupBy.map(col): _*).agg(exprs.head, exprs.tail: _*).show
// +---+------+------+------+
// |  k|min(v)|max(v)|avg(v)|
// +---+------+------+------+
// |  1|   3.0|   3.0|   3.0|
// |  2|  -5.0|  -5.0|  -5.0|
// +---+------+------+------+

ou

df.groupBy(groupBy.head, groupBy.tail: _*).agg(exprs.head, exprs.tail: _*).show

Malheureusement, l'analyseur utilisé en interne SQLContext n'est pas exposé publiquement, mais vous pouvez toujours essayer de construire des requêtes SQL en clair:

df.registerTempTable("df")
val groupExprs = groupBy.mkString(",")
val aggExprs = aggregate.flatMap(c => operations.map(
  f => s"$f($c) AS ${c}_${f}")
).mkString(",")

sqlContext.sql(s"SELECT $groupExprs, $aggExprs FROM df GROUP BY $groupExprs")

Python :

from pyspark.sql.functions import mean, sum, max, col

df = sc.parallelize([(1, 3.0), (1, 3.0), (2, -5.0)]).toDF(["k", "v"])
groupBy = ["k"]
aggregate = ["v"] 
funs = [mean, sum, max]

exprs = [f(col(c)) for f in funs for c in aggregate]

# or equivalent df.groupby(groupBy).agg(*exprs)
df.groupby(*groupBy).agg(*exprs)
41
zero323

Pour ceux qui se demandent, comment @ zero323 peut être écrit sans compréhension de liste en python:

from pyspark.sql.functions import min, max, col
# init your spark dataframe

expr = [min(col("valueName")),max(col("valueName"))]
df.groupBy("keyName").agg(*expr)
1
Zephro