【问题标题】:Relative frequency of pair of words in scalascala中词对的相对频率
【发布时间】:2018-09-20 03:31:01
【问题描述】:

我是scala 的新手,可能这就是为什么会有这些小疑问。 我有一些像("The", "band"),("The", "show"),("done", "by"),("The", "band"),("done", "that") 这样的元组发生2 次,并且以单词“The”开头的对数是3

因此相对频率对(The,band)将是

  • 2/3 = 0.66

所以我最终想要的应该是这样的((The, band),0.66) ((The, show), 0.33) ((done, by), 0.5) ((done, that), 0.5)


到目前为止我所做的是 - 我的变量 items1 包含我提到的所有上述对,

val result = items1.map(x=>(x->1)).reduceByKey(_+_)

这给了我这样的东西 - ((The, band), 2) ((The, show), 1) ((done, by), 1) ((done, that), 1)

现在我还想要以单词“The”或“done”开头的对数,以便我可以应用除法运算。我能够在一个单独的变量中找到从第一个单词开始的对数,但是我无法将其除以。

【问题讨论】:

    标签: scala


    【解决方案1】:

    这将起作用:

    def calcFreqs(xs: List[(String, String)]): Seq[((String, String), Double)] = {
      val den = xs.groupBy(_._1).mapValues(_.length)   // Map(word1, counts)
      xs.groupBy(identity)                           
        .mapValues(_.length)                           // Map(pair, counts)
        .toSeq                                         // Seq(pair, counts)
        .map{ case ((word1, word2), num) => 
          ((word1, word2), num.toDouble / den(word1))} // Seq(pair, pair/word1 ratio) 
    }
    

    【讨论】:

    • 有趣。你能描述一下步骤吗?
    • @J.Chomel 添加 cmets 这样做
    【解决方案2】:

    鉴于您尝试使用reduceByKey,我假设您正在处理的数据集是 Spark RDD。这是一种使用groupByKey 并将结果映射值分组来计算单个单词出现百分比的方法:

    val rdd = sc.parallelize(Seq(
      ("The", "band"), ("The", "show"), ("done", "by"), ("The", "band"), ("done", "that")
    ))
    
    rdd.groupByKey.mapValues{ arr =>
        arr.groupBy(identity).mapValues(_.size.toDouble / arr.size).toSeq
      }.
      flatMap{ case (k, vs) => vs.map(v => ((k, v._1), v._2)) }.
      collect
    // res1: Array[((String, String), Double)] = Array(
    //  ((The,band),0.66), ((The,show),0.33), ((done,that),0.5), ((done,by),0.5)
    // )
    

    如果它是一个普通的 Scala 集合,reduceByKeygroupByKey 都不是有效的方法。使用groupBy 的解决方案将类似,但由于其与RDD 的groupByKey 的方法签名不同,因此略有不同:

    val list = List(
      ("The", "band"), ("The", "show"), ("done", "by"), ("The", "band"), ("done", "that")
    )
    
    list.groupBy(_._1).mapValues{ ls =>
        ls.groupBy(identity).mapValues(_.size.toDouble / ls.size)
      }.
      flatMap(_._2).toList
    // res1: List[((String, String), Double)] = List(
    //   ((done,by),0.5), ((done,that),0.5), ((The,band),0.66), ((The,show),0.33)
    // )
    

    【讨论】:

    • 感谢 Leo 的回复。我尝试了您使用 groupByKey 的第一种技术。我写了 - val rdd = sc.parallelize(Seq(items1)) 但之后它说“值 groupByKey 不是 org.apache.spark.rdd.RDD[org.apache.spark.rdd.RDD[(String , 细绳)]]”。这不是使用 sc.parallelize 的正确方法吗?
    • @Sam,从您的错误消息来看,您似乎有一个嵌套的RDD[RDD[(String, String)]]。问题中提到的您的items1 应该已经是RDD[(String, String)]。也就是说,您可以直接将groupByKey 应用到items1,例如:items1.groupByKey.mapValues{...}.flatMap{...}
    【解决方案3】:

    您首先需要将所需的数字计算成Map,以便您可以在Constant时间查询它们。这样你就可以在O(n)时间得到最终结果。

    val items = List(("The","band"),("The","show"),("done","by"),("The","band"),("done","that"))
    // items: List[(String, String)] = List((The,band), (The,show), (done,by), (The,band), (done,that))
    
    val firstWordCountMap = items.foldLeft(Map.empty[String, Int])({case (accMap, (first, second)) =>
      accMap + (first -> (accMap.getOrElse(first, 0) + 1))
    })
    // firstWordCountMap: scala.collection.immutable.Map[String,Int] = Map(The -> 3, done -> 2)
    
    val itemsCountMap = items.foldLeft(Map.empty[(String, String), Int])({case (accMap, item) =>
      accMap + (item -> (accMap.getOrElse(item, 0) + 1))
    })
    // itemsCountMap: scala.collection.immutable.Map[(String, String),Int] = Map((The,band) -> 2, (The,show) -> 1, (done,by) -> 1, (done,that) -> 1)
    
    val itemsRatioList = itemsCountMap.map({ case ((first, second), count) =>
      ((first, second), count.toDouble / firstWordCountMap(first))
    }).toList
    // itemsRatio: List[((String, String), Double)] = List(((The,band),0.6666666666666666), ((The,show),0.3333333333333333), ((done,by),0.5), ((done,that),0.5))
    

    【讨论】:

      【解决方案4】:

      给定元组列表:

      val items =List(("The","band"),("The","show"),("done","by"),("The","band"),("done","that"))
      

      使用:

       def  rFreq(items:List[(String,String)]) = {
       val a1 = items.groupBy(identity).map(x=>(x._1,x._2.size))
       val a2 = items.groupBy(_._1).map(x=>(x._1,x._2.size))
       a1.map(x=>(x._1,x._2*1.0/a2.get(x._1._1).get))
       }
      

      在 Scala REPL 中:

      scala> rFreq(items)
      res99: scala.collection.immutable.Map[(String, String),Double] = Map((The,band) -> 0.6666666666666666, (The,show) -> 0.33333
      33333333333, (done,by) -> 0.5, (done,that) -> 0.5)
      

      【讨论】:

      • 这将是O(n^2)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-05
      • 2014-08-25
      • 1970-01-01
      • 2018-09-04
      • 1970-01-01
      • 2022-08-18
      相关资源
      最近更新 更多