近似百分数的计算

问题描述 投票:0回答:1

使用火花时 percentiles_approx 函数来计算声明式SQL中的近似百分数,有时分组我观察到这个函数的速度慢得令人痛苦。我已经将准确度降低到100(大约需要5分钟的聚合时间)或者有时1000(20-30分钟)。这比默认的1万精度低了10倍。

我观察到结果的百分比有点匹配,但当真正进入细节并计算它的许多组,即每天一个,他们根本不匹配.事实上,当预聚合数据尽可能多,并保留所有数字列(即放弃任何非数字内存密集型列)时,可以使用简单的pandas中值,这是1)精确的,2)比Spark快。

我是不是选择的精度太低了?但是1000已经需要非常长的时间来计算(我有>>1个聚合),所以5与25分钟很快就倍增了。

潘达斯怎么会这么快?由于矢量化的原因?

这里关于速度-精度的权衡,合适的参数是什么?

t-digest会不会 https:/github.comtdunningt-digest。

apache-spark percentile approximation
1个回答
0
投票

只要每个键的状态足够小,我将应用下面的代码来使用UDF计算百分位数.由于这需要更新版本的微风(可能会重复一些东西或有一些副作用,我将复制粘贴微风的一些部分)。

val r = scala.util.Random
val numbers = for (i <- 0 to 20) yield (r.nextDouble)

// in reality spark sort_array(collect_list()) will ensure already pre-sorted condition for the array
val sortedNumbers = numbers.sorted

/https:/github.comscalanlpbreezeblobmastermathsrcmainscalabreezestatsDescriptiveStats.scala#L537。

/**
 * Returns the estimate of a pre-sorted array at p * it.size, where p in [0,1].
 * <p>
 * Note:
 * Result is invalid if the input array is not already sorted.
 * </p>
 */
def percentileInPlace(arr: Array[Double], p: Double) = {
  if (p > 1 || p < 0) throw new IllegalArgumentException("p must be in [0,1]")
  // +1 so that the .5 == mean for even number of elements.
  val f = (arr.length + 1) * p
  val i = f.toInt
  if (i == 0) arr.head
  else if (i >= arr.length) arr.last
  else {
    arr(i - 1) + (f - i) * (arr(i) - arr(i - 1))
  }
}
percentileInPlace(sortedNumbers.toArray, 0.4)
percentileInPlace(sortedNumbers.toArray, 0.5)
percentileInPlace(sortedNumbers.toArray, 0.6)

这很容易计算出UDF中的各种百分比,并在需要时返回一个多百分比的数组。

注意:使用 .asNondeterministic() 当你打算从UDF中返回> 1个值以节省时间时。否则spark将分别计算collect_listsort_array和为每个百分位数(可能)由于催化剂的优化)当多列(=结构字段)输出)。

© www.soinside.com 2019 - 2024. All rights reserved.