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

pck*_*kmn 15 hadoop scala bigdata apache-spark

页面包含一些统计函数(均值,stdev,方差等),但不包含中位数.如何计算准确的中位数?

谢谢

Eug*_*nev 19

您需要对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
Run Code Online (Sandbox Code Playgroud)

  • ps:我认为有更快的算法可以找到不需要完全排序的中位数(http://en.wikipedia.org/wiki/Selection_algorithm) (2认同)

Sha*_*ica 5

使用Spark 2.0+和DataFrame API可以使用该approxQuantile方法吗?

def approxQuantile(col: String, probabilities: Array[Double], relativeError: Double)
Run Code Online (Sandbox Code Playgroud)

从Spark版本2.2开始,它还将同时在多个列上工作。通过将和设置 probabilites为0,它将计算出精确的中位数。从文档中Array(0.5)relativeError

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

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


一个小的工作示例,它计算1到99之间的数字中位数(包括两端值),并使用low relativeError

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

返回的中位数为50.0。