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

How can I calculate exact median with Apache Spark?

这个page包含一些统计函数(均值、标准差、方差等)但不包含中位数。如何计算准确的中位数?

需要对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

使用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:

The relative target precision to achieve (greater than or equal to 0). If set to zero, the exact quantiles are computed, which could be very expensive.

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


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

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

返回的中位数是 50.0。