如何找到Spark RDD的平均值?

时间:2018-07-09 00:00:20

标签: scala apache-spark mapreduce rdd

我已经阅读到reduce函数必须是可交换的和关联的。我应该如何编写函数以找到平均值,使其符合此要求?如果我将以下函数用于计算rdd的平均值,它将无法正确计算平均值。谁能解释我的功能出了什么问题?
我猜想它需要两个元素(例如1、2)并将函数应用于它们,例如(1 + 2)/ 2。然后将结果与下一个元素3相加,然后除以2等。

val rdd = sc.parallelize(1 to 100)

rdd.reduce((_ + _) / 2)

2 个答案:

答案 0 :(得分:2)

  

rdd.reduce((_ + _)/ 2)

上述reduce方法的平均计算存在一些问题:

  1. placeholder语法不能用作reduce((acc, x) => (acc + x) / 2)的简写
  2. 由于RDD的类型为整数,因此rdd.reduce((acc, x) => (acc + x) / 2)将在每次迭代中产生integer division(对于计算平均值肯定不正确)
  3. reduce方法不会产生列表的平均值。例如:

    List[Double](1, 2, 3).reduce((a, x) => (a + x) / 2)
    --> (1.0 + 2.0) / 2 = 1.5
    --> (1.5 + 3.0) / 2 = 2.25
    Result: 2.25
    

    而:

    Average of List[Double](1, 2, 3) = 2.0
    
  

我应该如何编写[reduce]函数来找到平均值,使其符合此要求?

我不确定reduce是否适合直接计算列表的平均值。您当然可以使用reduce(_ + _)对列表求和,然后将总和除以其大小,例如:

rdd.reduce(_ + _) / rdd.count.toDouble

但是您可以简单地使用RDD的内置函数mean

rdd.mean

答案 1 :(得分:1)

您还可以使用PairRDD来跟踪所有元素的总和以及元素计数。

val pair = sc.parallelize(1 to 100)
.map(x => (x, 1))
.reduce((x, y) => (x._1 + y._1, x._2 + y._2))

val mean = pair._1 / pair._2