将单词ngrams映射到scala中的计数

时间:2014-11-03 11:36:37

标签: scala nlp n-gram

我试图创建一张遍历文档中所有ngrams的地图,并计算它们出现的频率。 Ngrams是句子中n个连续单词的集合(因此在最后一句中,(Ngrams,are)是2-gram,(are,sets)是下一个2-gram,依此类推)。我已经有了从文件创建文档并将其解析为句子的代码。我还有一个函数来计算句子中的ngrams,ngramsInSentence,它返回Seq [Ngram]。

我在语法上遇到了如何创建我的计数贴图的问题。我在for循环中迭代文档中的所有ngrams,但不知道如何将nmap映射到它们出现频率的计数。我对Scala相当陌生,语法正在躲避我,尽管我在概念上清楚地表达了我需要的东西!

def getNGramCounts(document: Document, n: Int): Counts = {
    for (sentence <- document.sentences; ngram <- nGramsInSentence(sentence,n))
      //I need code here to map ngram -> count how many times ngram appears in document
}

上面的计数类型以及Ngram定义为:

type Counts = Map[NGram, Double]
type NGram = Seq[String]

有没有人知道将n循环从for循环映射到它们发生频率的计数的语法?如果您想了解有关此问题的更多详细信息,请与我们联系。

2 个答案:

答案 0 :(得分:2)

如果我正确地解释你的代码,这是一个相当常见的任务。

def getNGramCounts(document: Document, n: Int): Counts = {
  val allNGrams: Seq[NGram] = for {
    sentence <- document.sentences
    ngram <- nGramsInSentence(sentence, n)
  } yield ngram

  allNgrams.groupBy(identity).mapValues(_.size.toDouble)
}

allNGrams变量收集文档中出现的所有NGrams的列表 如果文档很大并且您无法将整个序列保存在内存中,则最终应转向Stream

以下groupBy创建了一个Map[NGram, List[NGram]],它按照标识对您的值进行分组(方法的参数定义了“聚合标识”的标准),并将相应的值分组到列表中。

然后,您只需将值(List[NGram])映射到其size,即可获得每个NGram的重复值。


我理所当然地认为:

  1. NGram正确实现了equals + hashcode
  2. document.sentences返回Seq[...]。如果不是,您应该期望allNGrams属于相应的集合类型。

  3. 根据评论

    更新

    我错误地认为groupBy(_)会快捷输入值。请改用identity功能。

    我将计数转换为Double

答案 1 :(得分:0)

感谢帮助 - 我现在使用上面的建议获得了正确的代码。以下内容返回所需的结果:

def getNGramCounts(document: Document, n: Int): Counts = {
  val allNGrams: Seq[NGram] = (for(sentence <- document.sentences; 
                                   ngram <- ngramsInSentence(sentence,n)) 
                                yield ngram)
  allNGrams.groupBy(l => l).map(t => (t._1, t._2.length.toDouble))
}