如何计算Spark中由(Key,[Value])对组成的RDD中每对的平均值?

时间:2015-06-18 15:46:29

标签: scala apache-spark

我对Scala和Spark都很陌生,所以请原谅我,如果我正在解决这个错误的错误。在获取csv文件,过滤和映射之后;我有一个RDD,它是一堆(String,Double)对。

(b2aff711,-0.00510)
(ae095138,0.20321)
(etc.)

当我在RDD上使用.groupByKey()时,

val grouped = rdd1.groupByKey()

获得带有一堆(String,[Double])对的RDD。 (我不知道CompactBuffer的意思,也许可能导致我的问题?)

(32540b03,CompactBuffer(-0.00699, 0.256023))
(a93dec11,CompactBuffer(0.00624))
(32cc6532,CompactBuffer(0.02337, -0.05223, -0.03591))
(etc.)

一旦他们被分组,我试图取平均值和标准差。我想简单地使用.mean()和.sampleStdev()。当我尝试创建新的RDD时,

val mean = grouped.mean()

返回错误

  

错误:(51,22)value mean不是org.apache.spark.rdd.RDD的成员[(String,Iterable [Double])]

     
    

val mean = grouped.mean()

  

我导入了org.apache.spark.SparkContext._
我也尝试使用sampleStdev(),. sum(),. stats(),结果相同。无论出现什么问题,它似乎都会影响所有数字RDD操作。

3 个答案:

答案 0 :(得分:4)

让我们考虑以下几点:

val data = List(("32540b03",-0.00699), ("a93dec11",0.00624),
                ("32cc6532",0.02337) , ("32540b03",0.256023),
                ("32cc6532",-0.03591),("32cc6532",-0.03591))

val rdd = sc.parallelize(data.toSeq).groupByKey().sortByKey()

计算每对的均值的一种方法如下:

您需要定义一个平均方法:

def average[T]( ts: Iterable[T] )( implicit num: Numeric[T] ) = {
   num.toDouble( ts.sum ) / ts.size
}

您可以按照以下方式在rdd上应用您的方法:

val avgs = rdd.map(x => (x._1, average(x._2)))

您可以查看:

avgs.take(3)

这就是结果:

res4: Array[(String, Double)] = Array((32540b03,0.1245165), (32cc6532,-0.016149999999999998), (a93dec11,0.00624))

答案 1 :(得分:1)

主持方式是使用reduceByKey代替groupByKey

val result = sc.parallelize(data)
  .map { case (key, value) => (key, (value, 1)) }
  .reduceByKey { case ((value1, count1), (value2, count2))
    => (value1 + value2, count1 + count2)}
  .mapValues {case (value, count) =>  value.toDouble / count.toDouble}

另一方面,解决方案中的问题是grouped形式为(String, Iterable[Double])的对象的RDD(就像在错误中一样)。例如,您可以计算Ints或double的RDD的平均值,但是对的rdd的平均值是什么。

答案 2 :(得分:1)

这是一个没有自定义功能的完整程序:

val conf = new SparkConf().setAppName("means").setMaster("local[*]")
val sc = new SparkContext(conf)

val data = List(("Lily", 23), ("Lily", 50),
                ("Tom", 66), ("Tom", 21), ("Tom", 69),
                ("Max", 11), ("Max", 24))

val RDD = sc.parallelize(data)

val counts = RDD.map(item => (item._1, (1, item._2.toDouble)) )
val countSums = counts.reduceByKey((x, y) => (x._1 + y._1, x._2 + y._2) )
val keyMeans = countSums.mapValues(avgCount => avgCount._2 / avgCount._1)

for ((key, mean) <- keyMeans.collect()) println(key + " " + mean)