Как сгруппировать слова по частоте их употребления в одном предложении?

У меня есть текст, 500 предложений. Предложения четко разграничены, для простоты предположим точку. В каждом предложении около 10-20 слов.

Я хочу разбить его на группы слов, которые по статистике чаще всего используются в одном и том же предложении. Вот простой пример.

This is a sentence about pink killer cats chasing madonna.
Sometimes when whales fight bricklayers, everyone drinks champaigne.
You know Madonna has little cats on her slippers.
When whales drink whiskey, your golf game is over.

У меня есть список стоп-слов, которые отфильтровываются, в случае выше я мог представить, что хочу создать эти группы.

группа 1: розовые кошки madonna
группа 2: киты пьют, когда

Или что-то вроде того. Я понимаю, что это может быть довольно сложной задачей. Я экспериментировал с подобием TF IDF и пока ничего не добился. Я работаю в рубине и хотел бы услышать любые мысли/направления/предложения людей.


person Jared Smith    schedule 24.06.2015    source источник
comment
Добро пожаловать в Stack Overflow. Мы хотели бы увидеть вашу попытку кода и конкретные вопросы, касающиеся вашей попытки решить проблему, а не генерировать для вас пулю идей.   -  person the Tin Man    schedule 25.06.2015


Ответы (1)


Мне понравилась головоломка, и вот мое видение возможного решения*...

* хотя, я бы порекомендовал вам в следующий раз не просто забрасывать свой вопрос, не показывая, что вы пробовали и где застряли... Иначе может показаться, что вы забрасываете нас своим домашним заданием. ..

Предположим, что это наш текст:

text = 'This is a sentence about pink killer cats chasing madonna.
        Sometimes when whales fight bricklayers, everyone drinks champaigne.
        You know Madonna has little cats on her slippers.
        When whales drink whiskey, your golf game is over.'

Мне кажется, что есть несколько этапов выполнения задач...

  1. Создайте каталог слов.

  2. Подсчитайте, сколько раз каждое слово встречается в тексте.

    require 'strscan'
    words = {}
    scn = StringScanner.new(text.downcase)
    ( words[scn.matched] =  words[scn.matched].to_i + 1 if scn.scan(/[\w]*/) ) while (scn.skip(/[^\w]*/) > 0) || !scn.eos?
    
  3. Удалите любое слово, которое встречается только один раз — оно не имеет значения.

    words.delete_if {|w, v| v <= 1}
    
  4. разбить текст на строчные предложения.

  5. Сделайте sentences => relevant_words_used хеш.

    sentences = {}
    text.downcase.split(/\.[\s]*/).each {|s| sentences[s] = []}
    
  6. Заполните предложения Hash словами, используемыми в каждом предложении. Ниже приведен упрощенный способ сделать это (в реальном приложении вам нужно будет разделить слова, чтобы слова «кошка» и «гусеница» не перекрывались):

    words.each {|w, c| sentences.each {|s, v| v << w if s.include? w} }
    

    пример для более сложной версии:

    sentences.each {|s, v| tmp = s.split(/[^\w]+/); words.each {|w, c| v << w if tmp.include? w} }
    
  7. Ваши группы находятся в массиве sentences.values. Теперь пришло время найти общие группы и посчитать, сколько раз они повторяются.

    common_groups = {}
    tmp_groups = sentences.values
    until tmp_groups.empty?
       active_group = tmp_groups.pop
       tmp_groups.each do |g|
            common = active_group & g
            next if common.empty?
            common_groups[common] = [2,(common_groups[common].to_i + 1)].max
       end
    end
    

Вуаля, это общие группы:

common_groups.each {|g, c| puts "the word(s) #{g} were common to #{c} sentences."}

# => the word(s) ["is"] were common to 2 sentences.
# => the word(s) ["when", "whales"] were common to 2 sentences.
# => the word(s) ["cats", "madonna"] were common to 2 sentences.

Весь код может выглядеть так:

text = 'This is a sentence about pink killer cats chasing madonna.
        Sometimes when whales fight bricklayers, everyone drinks champaigne.
        You know Madonna has little cats on her slippers.
        When whales drink whiskey, your golf game is over.'

require 'strscan'
text.downcase!
words = {}
scn = StringScanner.new(text)

( words[scn.matched] =  words[scn.matched].to_i + 1 if scn.scan(/[\w]*/) ) while (scn.skip(/[^\w]*/) > 0) || !scn.eos?

words.delete_if {|w, v| v <= 1}

sentences = {}
text.split(/\.[\s]*/).each {|s| sentences[s] = []}

# # A better code will split the sentences into words to
# # avoid partial recognition (cat vs. caterpillar).
# # for example:
sentences.each {|s, v| tmp = s.split(/[^\w]+/); words.each {|w, c| v << w if tmp.include? w} }
# # The following is the simplified version above:
# words.each {|w, c| sentences.each {|s, v| v << w if s.include? w} }

common_groups = {}
tmp_groups = sentences.values
until tmp_groups.empty?
   active_group = tmp_groups.pop
   tmp_groups.each do |g|
        common = active_group & g
        next if common.empty?
        common_groups[common] = [2,(common_groups[common].to_i + 1)].max
   end
end

common_groups.each {|g, c| puts "the word(s) #{g} were common to #{c} sentences."}

# => the word(s) ["is"] were common to 2 sentences.
# => the word(s) ["when", "whales"] were common to 2 sentences.
# => the word(s) ["cats", "madonna"] were common to 2 sentences.

ИЗМЕНИТЬ

Я исправил проблему с кодом, из-за которой текст не сохранялся в нижнем регистре. (text.downcase! против text.downcase)

ИЗМЕНИТЬ2

Я рассмотрел вопрос о проблемах с частичными словами (например, cat против caterpillar или dog против dogma)

person Myst    schedule 24.06.2015