如何使用 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。
这个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。