是否有一种干净的方法来计算Spark Dataframe上的移动百分位数。
我有一个巨大的数据框,我每15分钟聚合一次,我想计算每个部分的百分位数。
df.groupBy(window(col("date").cast("timestamp"), "15 minutes"))
.agg(sum("session"),mean("session"),percentile_approx("session", 0.5))
.show()
错误:未找到:value percentile_approx
所以我必须计算基本的东西,如总和和平均值,但我需要计算中位数和其他一些百分位数。
在Spark 2.1中有一种有效的方法吗?
因为在这里,似乎没有在API中实现的中值, percentile_approx , Percentile_approx 函数。
我看到这个问题已被提出,但答案并非都是一致的解决方案。这对我来说非常模糊......所以我想知道2017年8月是否有一个好的有效解决方案。
当我浏览15分钟的窗口时,我想知道是否只是硬计算它不会起作用而不是近似值?
非常感谢您的关注,
祝你下午好!
PS:Scala或PySpark我不介意,两者都会更大!
答案 0 :(得分:1)
如果您不需要滑动(重叠)窗口,可以使用groupBy执行此操作。 AFAIK没有百分位聚合函数,因此您需要实现自己的UDAF或使用以下方法:
val df = (1 to 100).map( i => (
i/10, scala.util.Random.nextDouble)
).toDF("time","session")
val calcStats = udf((data:Seq[Double]) => {
(data.sum,
data.sum/data.size,
data.sorted.apply(data.size/2) // is ~ median, replace with your desired logic
)
})
df.groupBy($"time")
.agg(collect_list($"session").as("sessions"))
.withColumn("stats",calcStats($"sessions").cast("struct<sum:double,mean:double,median:double>"))
.select($"time",$"stats.*")
.orderBy($"time")
.show
+----+------------------+-------------------+-------------------+
|time| sum| mean| median|
+----+------------------+-------------------+-------------------+
| 0|3.5441618790222287| 0.3937957643358032| 0.3968893251191352|
| 1|3.6612518806543757| 0.3661251880654376| 0.4395039388994335|
| 2| 4.040992655970037|0.40409926559700365| 0.3522214051715915|
| 3| 4.583175830988081| 0.4583175830988081| 0.5800394949546751|
| 4| 3.849409207658501| 0.3849409207658501|0.43422232330495936|
| 5| 5.514681139649785| 0.5514681139649784| 0.6703416471647694|
| 6| 4.890227540935781| 0.4890227540935781| 0.5515164635420178|
| 7|4.1148083531280095|0.41148083531280094| 0.4384132796986667|
| 8| 5.723834881155167| 0.5723834881155166| 0.6415902834329499|
| 9| 5.559212938582014| 0.5559212938582014| 0.6816268800227596|
| 10|0.8867335786067405| 0.8867335786067405| 0.8867335786067405|
+----+------------------+-------------------+-------------------+
答案 1 :(得分:1)
好的,我猜我真傻。
我只需将 callUDF 添加到我之前的想法中: percentile_approx 。对不起意见
callUDF("percentile_approx", col("session"), lit(0.5))
因此,例如在我的案例中,我希望每分钟汇总两个月的历史数据集:
df.groupBy(window((col("date")/1000).cast("timestamp"), "1 minutes"))
.agg(sum("session"),mean("session"),callUDF("percentile_approx", col("session"), lit(0.5)))
.show()
(以毫秒为单位的时间戳,因此 / 1000 )