Как использовать приблизительно количество по группе? - PullRequest
0 голосов
/ 30 ноября 2018

Spark имеет функцию SQL percentile_approx(), а его аналог Scala равен df.stat.approxQuantile().

Однако аналог Scala нельзя использовать для сгруппированных наборов данных, что-то вроде df.groupby("foo").stat.approxQuantile(), как показано здесь: https://stackoverflow.com/a/51933027.

Но возможно выполнять группирование и процентили в синтаксисе SQL.Поэтому мне интересно, может быть, я могу определить функцию UDF из SQL percentile_approx и использовать ее в своем сгруппированном наборе данных?

1 Ответ

0 голосов
/ 30 ноября 2018

Хотя вы не можете использовать approxQuantile в UDF, и у вас нет оболочки Scala для percentile_approx, нетрудно реализовать ее самостоятельно:

import org.apache.spark.sql.functions._
import org.apache.spark.sql.Column
import org.apache.spark.sql.catalyst.expressions.aggregate.ApproximatePercentile


object PercentileApprox {
  def percentile_approx(col: Column, percentage: Column, accuracy: Column): Column = {
    val expr = new ApproximatePercentile(
      col.expr,  percentage.expr, accuracy.expr
    ).toAggregateExpression
    new Column(expr)
  }
  def percentile_approx(col: Column, percentage: Column): Column = percentile_approx(
    col, percentage, lit(ApproximatePercentile.DEFAULT_PERCENTILE_ACCURACY)
  )
}

Пример использования:

import PercentileApprox._

val df = (Seq.fill(100)("a") ++ Seq.fill(100)("b")).toDF("group").withColumn(
  "value", when($"group" === "a", randn(1) + 10).otherwise(randn(3))
)

df.groupBy($"group").agg(percentile_approx($"value", lit(0.5))).show
+-----+------------------------------------+
|group|percentile_approx(value, 0.5, 10000)|
+-----+------------------------------------+
|    b|                -0.06336346702250675|
|    a|                   9.818985618591595|
+-----+------------------------------------+
df.groupBy($"group").agg(percentile_approx($"value", typedLit(Seq(0.1, 0.25, 0.75, 0.9)))).show(false)
+-----+----------------------------------------------------------------------------------+
|group|percentile_approx(value, [0.1,0.25,0.75,0.9], 10000)                              |
+-----+----------------------------------------------------------------------------------+
|b    |[-1.2098351202406483, -0.6640768986666159, 0.6778253126144265, 1.3255676906697658]|
|a    |[8.902067202468098, 9.290417382259626, 10.41767257153993, 11.067087075488068]     |
+-----+----------------------------------------------------------------------------------+

Как только это происходит в пути к классам JVM, вы также можете добавить оболочку PySpark, используя логику, аналогичную встроенным функциям.

...