igo-rubyとjubatusを使ってみよう　〜文章の解析編〜

#まとめ

・導入ちょっと面倒
・pythonでMeCab/scipy使ったりjrubyでMahout使ったりが合理的かも
・長い文章は重くてつらい
・だけど盛り上がってくれたら嬉しい

#参考にしたページ一覧

とりあえず入れるだけ入れてみた。（igoで行列モデルにした文章を特異値分解してk-近傍法とかしたい）
[jubatusクイックスタート](http://jubat.us/ja/quickstart.html#ruby)

wgetのかわりにcurl -oでやってみたけど上手く行かなかった
[[igo][Ruby]igoの辞書を作って、igo-rubyで形態素解析](http://d.hatena.ne.jp/shokai/20101231/1293760991)

結局、手動でダウンロードして辞書をビルド
[Java製形態素解析エンジン「Igo」を試してみる](http://www.mwsoft.jp/programming/munou/igo_install.html)

作成したメソッドの引数が文字化けしたので
[pryを日本語で使う](http://alifedesign.net/2012/06/irb%E3%81%A8pry%E3%81%A7%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%82%92%E4%BD%BF%E3%81%86/)

#ハマりポイント

形態素解析（文の適切な分解と品詞分け）を行うためには「辞書」が必要です。

その辞書のダウンロードと設置で手間取りました。

[igo ver0.4.5](http://sourceforge.jp/projects/igo/downloads/55029/igo-0.4.5.jar/)

をダウンロードしたあと

[MeCab IPA辞書](http://sourceforge.net/projects/mecab/files/mecab-ipadic/2.7.0-20070801/)

をダウンロードします。

```tar xzvf mecab-ipadic-2.7.0-20070801.tar.gz```

で辞書のほうのtarファイルを解凍します。
（何故か ```*.tar.tar.gz``` のように変な名前になってました。）

.gzですけどgunzipを使う必要はなかったはずです。

解凍後 ```net```というディレクトリが生成されると思います。

```java -cp igo-0.4.5.jar net.reduls.igo.bin.BuildDic ipadic mecab-ipadic-2.7.0-20070801 EUC-JP```

を実行して辞書をビルドすると```ipadic```というディレクトリの中にいろいろ入ってます。

これをRailsプロジェクトのassets直下に僕は置きました。

んで、pryで試しに

```ruby:igo-parse-test.rb

#!/usr/bin/env ruby
# -*- coding: utf-8 -*-

mes = ARGV.join(' ') unless ARGV.empty?
mes = "引数にparseしたい文章を入れて起動してね" unless mes

tagger = Igo::Tagger.new('./app/asset/ipadic')

puts tagger.wakati(mes)
tagger.parse(mes).each{|i|
  puts "#{i.surface} #{i.feature} #{i.start}"
}

```

を使ってみたかったのですが、pryは日本語が使えませんでした。

ruby2.0.0p353をアンインストールしたらrubygemsのextension-api-versionメソッドが調子悪くてハマったのでruby2.0.0p247を急遽起用。

pryを使わずに

```ruby:home_controller.rb

class HomeController < ApplicationController

  MES = "兄さん、兄さんが有限実行の志士なのはわかりましたから、5日分の牛肉やら白菜やらまとめ買いしてくるの、止して下さい…「こんなにすき焼きの材料買って…お餅は
何時食べるのですか…」「餅をすき焼きの中に入れればよい」兄さんのすき焼きに寄せる万能感、どこ から来てるの"

  def index
    igo MES
  end

  private

  def igo arg
    mes = arg unless arg.empty?
    mes = "引数にparseしたい文章を入れて起動してね" unless mes

    tagger = Igo::Tagger.new(File.join("#{Rails.root}", "app", "assets", "ipadic"))

    @wakati = tagger.wakati(mes)
    @igo = tagger.parse(mes)
  end
end

```

```html:~/home/index.html.erb

<h1>Home#index</h1>

<%= @wakati %>

<% @igo.each do |i| %>
  <%= "#{i.surface} #{i.feature} #{i.start}" %>
<% end %>

```

こんな感じにしてやると

![Screenshot 2014-02-08 00.17.02.png](https://qiita-image-store.s3.amazonaws.com/0/26475/a569f817-c4fb-cd09-68b7-b29d648e467a.png)


ちゃんと分かち書きと形態素解析できてますね。

次回は
・入力データを形態素解析
・結果を行列モデル化
・行列を特異値分解して縮約
・縮約した行列の任意の列のコサイン類似度の計算
あたりをjubatusでできたらなと思います。できるかどうかはわかりません。

それでは


#追記

任意の入力を受け付けて、きれいに表示できるようにしました。

```html:~home/index.html.erb

<h1>Home#index</h1>


<h2>解析文を入力してください</h2>

<%= simple_form_for :igo_form do |f| %>
  <%= f.error_notification %>
  <%= f.input :text, as: :text %>
  <div class="form-actions">
    <%= f.button :submit, class: 'btn-danger btn-large' %>
  </div>
<% end %>

<h2>入力</h2>

<p><%= @mes %></p>

<% if @igo %>
  <h2>分かち書き</h2>
  <p><%= @wakati %></p>
  <h2>形態素解析</h2>
  <table class="table table-striped table-bordered table-hover">
    <thead>
      <tr>
        <th>形態素の表層形</th>
        <th>形態素の素性</th>
        <th>テキスト内での形態素の出現開始位置</th>
      </tr>
    </thead>
    <tbody>
      <% @igo.each do |i| %>
        <tr>
          <td><%= "#{i.surface}" %></td>
          <td><%= "#{i.feature}" %></td>
          <td><%= "#{i.start}" %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
<% end %>

```

```ruby:home_controller.rb

class HomeController < ApplicationController
  def index
    igo params[:igo_form][:text].gsub(/(\r\n|\r|\n)/, "") if params[:igo_form]
  end

  private

  def igo arg
    @mes = arg.present? ? arg : "引数にparseしたい文章を入れて起動してね"

    tagger = Igo::Tagger.new(File.join("#{Rails.root}", "app", "assets", "ipadic"))

    @wakati = tagger.wakati(@mes)
    @igo = tagger.parse(@mes)
  end
end

```

```ruby:igo_form.rb

class IgoForm < ActiveRecord::Base
  extend ActiveModel::Naming
  include ActiveModel::Conversion

  attr_accessor :text

  def initialize(attributes = {})
    self.attributes = attributes
  end

  def attributes=(attributes = {})
    if attributes
      attributes.each do |name, value|
        send "#{name}=", value
      end
    end
  end

  def attributes
    Hash[instance_variable_names.map{|v| [v[1..-1], instance_variable_get(v)]}]
  end
end

```

こんな感じになりました

![Screenshot 2014-02-08 23.13.30.png](https://qiita-image-store.s3.amazonaws.com/0/26475/180aa84a-f8bc-8eea-fbf4-1092b6d2ef65.png)

![Screenshot 2014-02-08 23.13.39.png](https://qiita-image-store.s3.amazonaws.com/0/26475/b1ff2493-0b29-42a1-5052-365fc6dca1b6.png)

MeCabよりメソッド少なくて出力形式も少ないけどいまのところ気になるほどではないかなって思います。

拙いアレですが参考に成れば幸い