如何使用Apache Spark计算精确中位数?

时间:2015-01-26 21:04:09

标签: scala hadoop bigdata apache-spark

page包含一些统计函数(mean,stdev,variance等),但不包含中位数。我怎样才能计算出精确的中位数?

由于

2 个答案:

答案 0 :(得分:18)

您需要对RDD进行排序,并将元素放在两个元素的中间或平均值中。以下是RDD [Int]的示例:

  import org.apache.spark.SparkContext._

  val rdd: RDD[Int] = ???

  val sorted = rdd.sortBy(identity).zipWithIndex().map {
    case (v, idx) => (idx, v)
  }

  val count = sorted.count()

  val median: Double = if (count % 2 == 0) {
    val l = count / 2 - 1
    val r = l + 1
    (sorted.lookup(l).head + sorted.lookup(r).head).toDouble / 2
  } else sorted.lookup(count / 2).head.toDouble

答案 1 :(得分:4)

使用 Spark 2.0 + 和DataFrame API,您可以使用approxQuantile方法:

def approxQuantile(col: String, probabilities: Array[Double], relativeError: Double)

自Spark版本2.2起,它也可以同时在多个列上运行。通过将probabilites设置为Array(0.5)并将relativeError设置为0,它将计算确切的中位数。来自documentation

  

要达到的相对目标精度(大于或等于0)。如果设置为零,则计算精确的分位数,这可能非常昂贵。

尽管如此,将relativeError设置为0时似乎存在一些精度问题,请参阅问题here。接近0的低错误在某些情况下会更好地工作(取决于Spark版本)。

一个小工作示例,用于计算从1到99(包括两者)的数字的中位数,并使用低relativeError

val df = (0 to 99).toDF("num")
val median = df.stat.approxQuantile("num", Array(0.5), 0.001)(0)
println(median)

返回的中位数是50.0。