Mecabで単語の出現数を数えるには

はじめに

油断してるとあっという間に時間が経つ.
気がついたら5月ももう終わりです.


前々回まで集合知プログラミングの第3章をやってきた訳ですが,
ベイズフィルタを勉強したくなった関係で,第6章にいきなり飛びます.
今回は,本の中で登場する単語のカウンタです.

実行例

こんなふうに使います.
なお,Mecabがあらかじめインストールされている必要がありますよ.

counter = My::WordCounter.new
counter.count('今,私はドトールにいます')
counter.count('そして頑張ってデバッグしています')
counter.result.each do |word, count|
  puts "#{word} => #{count}"
end

結果はこんな感じ.

=> 1
デバッグ => 1
頑張っ => 1=> 1
ドトール => 1

ソース

module My
  class WordCounter
    MECAB = '/usr/local/bin/mecab'
    NECESSARY_FEATURE = %w/名詞,固有名詞 名詞,一般 名詞,副詞可能 名詞,サ変接続 動詞.*五段/
    UNNECESSARY_FEATURE = %w/名詞,数 名詞,接尾/

    def initialize
      @result = Hash.new(0)
    end

    attr_reader :result

    # mainループ
    def count(text)
      words = split_to_words(text)
      count_up_result(words)
      self
    end

    # Mecabで単語に分割し,必要な品詞のみ抽出する
    def split_to_words(text)
      results = IO.popen(MECAB, 'r+') { |mecab|
        mecab.puts(text)
        mecab.close_write
        mecab.readlines
      }
      results.map { |result| necessary?(result) ? result.split.first : nil }.compact
    end

    # 単語として使うする属性を判断する
    def necessary?(feature)
      case feature
      when Regexp.new(NECESSARY_FEATURE.join('|'))
        true
      when Regexp.new(UNNECESSARY_FEATURE.join('|'))
        false
      when /名詞/
        warn feature
        false
      else
        false
      end
    end

    # 単語数をカウント
    def count_up_result(words)
      words.each do |word|
        @result[word] += 1
      end
    end
  end
end

Rubyとのやりとり

IO.popenを使って,Mecabを呼び出してます.その後,mapで必要な品詞だけ取り出せばOK.
本当にRubyのブロックは便利で仕方がない.

def split_to_words(text)
  results = IO.popen(MECAB, 'r+') { |mecab|
    mecab.puts(text)
    mecab.close_write
    mecab.readlines
  }
  results.map { |result| necessary?(result) ? result.split.first : nil }.compact
end

最後に

実はMecabにはRubyバインディングもあるので,また書きます.