gpt4 book ai didi

scala - 如何在 Spark 中找到分组数据的确切中位数

转载 作者:行者123 更新时间:2023-12-04 02:08:19 27 4
gpt4 key购买 nike

我需要使用 Scala 计算 Spark 中 Double 数据类型的分组数据集的精确中位数。

它不同于类似的查询:Find median in spark SQL for multiple double datatype columns .这个问题是关于分组数据的查找数据,而另一个问题是关于在 RDD 级别上查找中位数。

这是我的示例数据

scala> sqlContext.sql("select * from test").show()

+---+---+
| id|num|
+---+---+
| A|0.0|
| A|1.0|
| A|1.0|
| A|1.0|
| A|0.0|
| A|1.0|
| B|0.0|
| B|1.0|
| B|1.0|
+---+---+

预期答案:

+--------+
| Median |
+--------+
| 1 |
| 1 |
+--------+

我尝试了以下选项,但没有成功:

1) Hive 函数百分位数,它只对 BigInt 有效。

2) Hive 函数 percentile_approx,但它没有按预期工作(返回 0.25 vs 1)。

scala> sqlContext.sql("select percentile_approx(num, 0.5) from test group by id").show()

+----+
| _c0|
+----+
|0.25|
|0.25|
+----+

最佳答案

最简单的方法(需要 Spark 2.0.1+ 而不是精确的中值)

如第一个问题的评论中所述 Find median in Spark SQL for double datatype columns ,我们可以使用 percentile_approx 来计算 Spark 2.0.1+ 的中位数。要将此应用于 Apache Spark 中的分组数据,查询将如下所示:

val df = Seq(("A", 0.0), ("A", 0.0), ("A", 1.0), ("A", 1.0), ("A", 1.0), ("A", 1.0), ("B", 0.0), ("B", 1.0), ("B", 1.0)).toDF("id", "num")
df.createOrReplaceTempView("df")
spark.sql("select id, percentile_approx(num, 0.5) as median from df group by id order by id").show()

输出为:

+---+------+
| id|median|
+---+------+
| A| 1.0|
| B| 1.0|
+---+------+

也就是说,这是一个近似值(而不是每个问题的精确中值)。

计算分组数据的精确中位数

有多种方法,所以我相信 SO 中的其他人可以提供更好或更有效的示例。但这里有一个代码片段计算 Spark 中分组数据的中位数(在 Spark 1.6 和 Spark 2.1 中验证):

import org.apache.spark.SparkContext._

val rdd: RDD[(String, Double)] = sc.parallelize(Seq(("A", 1.0), ("A", 0.0), ("A", 1.0), ("A", 1.0), ("A", 0.0), ("A", 1.0), ("B", 0.0), ("B", 1.0), ("B", 1.0)))

// Scala median function
def median(inputList: List[Double]): Double = {
val count = inputList.size
if (count % 2 == 0) {
val l = count / 2 - 1
val r = l + 1
(inputList(l) + inputList(r)).toDouble / 2
} else
inputList(count / 2).toDouble
}

// Sort the values
val setRDD = rdd.groupByKey()
val sortedListRDD = setRDD.mapValues(_.toList.sorted)

// Output DataFrame of id and median
sortedListRDD.map(m => {
(m._1, median(m._2))
}).toDF("id", "median_of_num").show()

输出为:

+---+-------------+
| id|median_of_num|
+---+-------------+
| A| 1.0|
| B| 1.0|
+---+-------------+

我应该提出一些注意事项,因为这可能不是最有效的实现方式:

  • 它当前使用的 groupByKey 性能不是很好。您可能希望将其更改为 reduceByKey(更多信息请参见 Avoid GroupByKey)
  • 使用 Scala 函数计算中位数

这种方法适用于少量数据,但如果每个键有数百万行,建议使用 Spark 2.0.1+ 并使用 percentile_approx 方法。

关于scala - 如何在 Spark 中找到分组数据的确切中位数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41431270/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com