2014-11-03 2 views
2

Я пытаюсь создать карту, которая проходит через все ngrams в документе и подсчитывает, как часто они появляются. Ngrams - это множества из n последовательных слов в предложении (так что в последнем предложении (Ngrams, are)) является 2-граммовым (are, sets) следующим 2-грамм и т. Д.). У меня уже есть код, который создает документ из файла и анализирует его в предложениях. У меня также есть функция, чтобы считать ngrams в предложении ngramsInSentence, который возвращает Seq [Ngram].Map word ngrams to counts scala

Я синтаксически зацикливаюсь на том, как создать карту подсчета. Я повторяю все ngrams в документе в цикле for, но не знаю, как сопоставить ngrams с подсчетом того, как часто они происходят. Я довольно новичок в 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 
} 

Тип COUNTS выше, а также Ngram, определяются как:

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

Кто-нибудь знает синтаксис для отображения на ngrams из цикл для подсчета того, как часто они происходят? Пожалуйста, дайте мне знать, если вы хотите получить более подробную информацию о проблеме.

+0

Нижеприведенный ответ выглядит как способ, но возвращает карту [Nothing, Int] вместо Map [NGram, Double], у кого есть идеи? – user3297367

ответ

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 будет соответствующего типа коллекции.

ОБНОВЛЕНО на основе комментариев

я ошибочно предполагалось, что groupBy(_) бы ярлык значение входного сигнала. Вместо этого используйте функцию identity.

я преобразовал счет в Double

+0

Спасибо, что нашли время, чтобы помочь. К сожалению, приведенное выше возвращает Map [Nothing, Int], а не тип Counts, реализованный как Map [NGram, Double], с использованием NGram как Seq [String]. Любая идея, что может быть неправильным? – user3297367

+0

Вы правы, что предложения возвращают Seq [Sentence]. Предложение выполняется в другом месте. – user3297367

+0

Голый '_' не работает, как вы ожидали в этом контексте. Вместо этого попробуйте '.groupBy (x => x)'. – lmm

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)) 
}