如何按火花分组分布?

时间:2018-11-07 06:30:47

标签: scala apache-spark dataframe

我正在寻找一种基于分布对列(int值)进行分组的方法。例如:

Df =

col1  col2
1a      10
2a      120 
3a      3 
4a      10000 
5a      10 

我正在尝试获得(0,1,5,10,50,100,10000)这样的分布:

distribution(lesser than or equal)           count
0                                               0
1                                               0
5                                               1
10                                              2
50                                              3
100                                             3
10000                                           5

是否可以使用Spark中的任何预定义数学函数轻松实现此目的?

1 个答案:

答案 0 :(得分:1)

因此,首先,我们可以计算目标列的百分位数。例如,假设我们计算1、5、10、25、50、75、90、95、99、100个分位数。

val df = Seq(1, 1, 2, 3, 5, 5, 5, 9, 9, 10, 12, 13, 15, 15, 16, 20, 200, 201, 205).toDF
val quantiles = List(0.01, 0.05, 0.10, 0.25, 0.50, 0.75, 0.90, 0.95, 0.99)
val quantsGenerator = for {
    a <- quantiles
  } yield callUDF("percentile_approx", col("value"), lit(a)).as("q" + a.toString)
val quantilesComputed = df.agg(count("*").as("count"), quantsGenerator: _*).drop("count")

因此,在第一个代码段中,我初始化了DF和分位数列表。对于每个分位数,我创建一个列,该列将作为该列上百分位数的计算。我的变量 quantsGenerator 包含将在agg函数中应用的每一列的表达式。

agg函数在您需要的Spark源代码中以某种方式进行编码,以便首先具有单个列(因此在这里我使用 count(“ *”)),然后您可以给varargs到 agg 函数,这里将是我们的quantGenerator。 count(“ *”)是无用的,只是对于我们能够为函数 agg 赋予变量。因此,您可以稍后将其删除。

一旦有了这个,我们就可以生成一个最终的数据框,即“ La fonction derépartition”,用法语:D

val quantsAsArrayDouble = quantilesComputed.collect.map(x => x.toSeq.asInstanceOf[Seq[Double]).flatten
val whenFunctions = quantsAsArrayDouble.map(x => sum(when(col("value") <= x.toDouble, 1)).as("<=" + x.toString))
val finalDf = df.agg(count(lit(1)).as("count"), whenFunctions: _*).drop("count")

再次获得此计数(“ *”)...哦,不! count(lit(1)),它是完全一样的。它被解释为count(“ *”),在我们的案例中,它对varWhen whenFunctions ... grrrr

有用。

最后,您获得了想要的东西。

scala> df.agg(count("*"),c:_*).show
+-----+-----+-----+-----+------+------+-------+-------+-------+-------+
|<=1.0|<=1.0|<=1.0|<=5.0|<=10.0|<=16.0|<=201.0|<=205.0|<=205.0|<=205.0|
+-----+-----+-----+-----+------+------+-------+-------+-------+-------+
|    2|    2|    2|    7|    10|    15|     18|     19|     19|     19|
+-----+-----+-----+-----+------+------+-------+-------+-------+-------+

经常重复使用多个相同的值,因为我没有足够的数据。但我很确定,这对于您的情况下的大量数据将非常有效。您可以通过修改第一个列表来选择所需的百分位数。

祝你好运

PS:在上一篇文章被分享时,我刚刚看到Spark中存在Bucketizer对象。是的,这可能比我的技术更有效x)我的糟糕! 玩Spark