いつでも発展途上

猫と珈琲とゲームが大好きです。ITエンジニアらしいです。メモ代わりにいろいろ書いています。

Windows + Ruby でマルコフ連鎖

マルコフ連鎖で日本語をもっともらしく要約する - ザリガニが見ていた...。 を見ていて面白そうだと思ったので、手元にあった Windows PC でやってみました。環境は以下のとおり。

以下、メモがわりに手順を書いておきます。
1) 形態素解析エンジン MeCabWindows バイナリをダウンロードしてインストールします。(文字コードShift_JIS にしました)
2) 言語処理関連のプログラム類 の "windowsrubyからlibmecab.dllを呼び出す" より mecab.rb をダウンロードします。
3) RubyGems から HTML 解析ライブラリ Nokogiri をインストールします。

gem install nokogiri

4) マルコフ連鎖で日本語をもっともらしく要約する - ザリガニが見ていた...。 にあるサンプルコードのうち以下を変更します。

また、44行目で生成した要約文を表示していますが、自分の場合 KconvShift_JIS に変換する必要がありました。

puts Kconv.tosjis new_text.gsub!(/EOS$/,''))

以上を行った結果、以下のようなコードとなりました。これを markov.rb として保存します。

require 'Mecab'
require 'rubygems'
require 'nokogiri'
require 'open-uri'

# ヘッドラインの1行目の記事を取得する
url = 'http://www.asahi.com/'
text = String.new
nokogiri = Nokogiri::HTML.parse(open(url))
li = nokogiri.xpath('//div[@id="HeadLine"]/ul[@class="Lnk FstMod"]/li[1]/a')
nokogiri = Nokogiri::HTML.parse(open(url + li[0].attribute('href')))
nokogiri.xpath('//div[@class="BodyTxt"]/*').each do |body|
  text = text + body.text
end
text.gsub!(/\n/,'')
 
# mecabで形態素解析して、 参照テーブルを作る
mecab = Mecab.new("-Owakati")
data = Array.new
mecab.sparse_tostr(text + "EOS").split(" ").each_cons(3) do |a|
  data.push h = {'head' => a[0], 'middle' => a[1], 'end' => a[2]}
end
 
# マルコフ連鎖で要約
t1 = data[0]['head']
t2 = data[0]['middle']
new_text = t1 + t2
while true
  _a = Array.new
  data.each do |hash|
    _a.push hash if hash['head'] == t1 && hash['middle'] == t2
  end
 
  break if _a.size == 0
  num = rand(_a.size) # 乱数で次の文節を決定する
  new_text = new_text + _a[num]['end']
  break if _a[num]['end'] == "EOS"
  t1 = _a[num]['middle']
  t2 = _a[num]['end']
end

# EOSを削除して、結果出力
puts Kconv.tosjis new_text.gsub!(/EOS$/,''))

あとは markov.rb と mecab.rb を同じディレクトリにおいて、

ruby markov.rb

とすると実行されます。
参考