这个 页面 包含了一些统计函数(如平均值、标准差、方差等),但没有中位数。我该怎么计算精确的中位数?
您需要对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)
probabilites
设置为 Array(0.5)
并将 relativeError
设置为 0,它将计算精确的中位数。从文档中可以看到:
尽管如此,当将实现相对目标精度(大于等于0)。如果设置为零,则计算精确分位数可能非常昂贵。
relativeError
设置为0时,似乎存在一些精度问题,请查看这里的问题here。在某些情况下,接近0的低误差会表现得更好(取决于Spark版本)。
relativeError
:val df = (1 to 99).toDF("num")
val median = df.stat.approxQuantile("num", Array(0.5), 0.001)(0)
println(median)
中位数为50.0。
percentile_approx
函数在具有偶数个条目的组中无法正常工作。为了使其在这种情况下正常工作,一个可能的解决方法是取第50百分位数和下一个值的平均值。在pyspark中,可以使用以下代码实现:((F.percentile_approx('val', 0.5) + F.percentile_approx('val', 0.500000000001)) * 0.5).alias('med_val2')
- prashanth