【问题标题】:Average word length in SparkSpark中的平均字长
【发布时间】:2016-01-13 01:05:40
【问题描述】:

我有一个值列表以及它们作为数组出现的所有值的聚合长度。

例如:如果我的句子是

"I have a cat. The cat looks very cute"

我的数组看起来像

Array((I,1), (have,4), (a,1), (cat,6), (The, 3), (looks, 5), (very ,4), (cute,4))

现在我想计算每个单词的平均长度。即出现的长度/次数。

我尝试使用 Scala 进行如下编码:

val avglen = arr.reduceByKey( (x,y) => (x, y.toDouble / x.size.toDouble) )

我在x.size 收到如下错误

错误:值大小不是 Int 的成员

请帮助我这里哪里出错了。

【问题讨论】:

  • 我正在寻找每个单词的平均长度(不是在整体文本级别),即如果一个单词的出现次数更多,我需要获得更多单词的平均长度。例如,我的段落中的单词 cat 出现了两次,因此该单词的平均长度是 6/3 =2 对于其他单词,例如“The”,平均长度是 3/3 =1

标签: scala apache-spark rdd


【解决方案1】:

在你的评论之后,我想我明白了:

val words = sc.parallelize(Array(("i", 1), ("have", 4), 
                                 ("a", 1), ("cat", 6), 
                                 ("the", 3), ("looks", 5), 
                                 ("very", 4), ("cute", 4)))

val avgs = words.map { case (word, count) => (word, count / word.length.toDouble) }

println("My averages are: ")
avgs.take(100).foreach(println)

假设您有一个包含这些单词的段落,并且您想要计算该段落单词的平均大小。

分两个步骤,使用map-reduce 方法和spark-1.5.1

val words = sc.parallelize(Array(("i", 1), ("have", 4), 
                                 ("a", 1), ("cat", 6), 
                                 ("the", 3), ("looks", 5), 
                                 ("very", 4), ("cute", 4)))

val wordCount = words.map { case (word, count) => count}.reduce((a, b) => a + b)
val wordLength = words.map { case (word, count) => word.length * count}.reduce((a, b) => a + b)

println("The avg length is: " +  wordLength / wordCount.toDouble)

我使用连接到spark-kernel 的 .ipynb 运行此代码,这是输出。

【讨论】:

  • 这不是所有单词的平均长度。该值表示该句子中该单词的所有字符的总计数(不是单词的计数!)。
  • @RohanAletty 我不确定他想要什么,这就是我所理解的,通常如果一个段落有一些单词并且你想计算平均值这是合适的方法
  • 请看我的回答,我相信这是发帖人要求的。本质上,字数已经汇总,因此键是唯一的。
  • 感谢 Eugene Zhulenev、Rohan Aletty、@Alberto Bonsanto 的回答。但是我正在寻找每个单词的平均单词长度。即如果一个词的出现次数更多,我需要得到这个词的平均长度。例如我的段落中的单词 cat 出现了两次,平均长度为 6/3 =2
  • 感谢@Alberto Bonsato 的帮助
【解决方案2】:

如果我正确理解问题:

val rdd: RDD[(String, Int) = ???
val ave: RDD[(String, Double) = 
     rdd.map { case (name, numOccurance) => 
       (name, name.length.toDouble / numOccurance)
     }

【讨论】:

    【解决方案3】:

    这是一个有点令人困惑的问题。如果您的数据已经在Array[(String, Int)] 集合中(大概在驱动程序的collect() 之后),那么您不需要使用任何RDD 转换。事实上,您可以使用 fold*() 运行一个绝妙的技巧来获取集合的平均值:

    val average = arr.foldLeft(0.0) { case (sum: Double, (_, count: Int)) => sum + count } / arr.foldLeft(0.0) { case (sum: Double, (word: String, count: Int)) => sum + count / word.length }
    

    有点啰嗦,但它基本上汇总了分子中的字符总数和分母中的单词数。运行您的示例,我看到以下内容:

    scala> val arr = Array(("I",1), ("have",4), ("a",1), ("cat",6), ("The", 3), ("looks", 5), ("very" ,4), ("cute",4))
    arr: Array[(String, Int)] = Array((I,1), (have,4), (a,1), (cat,6), (The,3), (looks,5), (very,4), (cute,4))
    
    scala> val average = ...
    average: Double = 3.111111111111111
    

    如果您的 (String, Int) 元组分布在 RDD[(String, Int)] 中,则可以使用 accumulators 轻松解决此问题:

    val chars = sc.accumulator(0.0)
    val words = sc.accumulator(0.0)
    wordsRDD.foreach { case (word: String, count: Int) =>
      chars += count; words += count / word.length
    }
    
    val average = chars.value / words.value
    

    在上面的示例上运行时(放置在RDD 中),我看到以下内容:

    scala> val arr = Array(("I",1), ("have",4), ("a",1), ("cat",6), ("The", 3), ("looks", 5), ("very" ,4), ("cute",4))
    arr: Array[(String, Int)] = Array((I,1), (have,4), (a,1), (cat,6), (The,3), (looks,5), (very,4), (cute,4))
    
    scala> val wordsRDD = sc.parallelize(arr)
    wordsRDD: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[0] at parallelize at <console>:14
    
    scala> val chars = sc.accumulator(0.0)
    chars: org.apache.spark.Accumulator[Double] = 0.0
    
    scala> val words = sc.accumulator(0.0)
    words: org.apache.spark.Accumulator[Double] = 0.0
    
    scala> wordsRDD.foreach { case (word: String, count: Int) =>
         |   chars += count; words += count / word.length
         | }
    ...
    scala>     val average = chars.value / words.value
    average: Double = 3.111111111111111
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 2018-09-27
      • 2020-12-05
      • 2021-04-17
      • 1970-01-01
      • 2017-03-05
      相关资源
      最近更新 更多