Ruby 1.9.2でMeCabを使う
MeCabで形態素解析
ツイートなんかを分析したいのなら、まずは形態素解析しなきゃオハナシにならないでしょ、と。たとえば「僕は杉山です。」って文を形態素っていう単位に分けて、その形態素の情報を得る、と。形態素の情報っていうのは読み方だとか品詞だとか活用だとか。
形態素解析をするには、いまではMeCabというソフトウェアを使うのがデファクトスタンダードです。
なので、僕のUbuntuにもMeCabを入れます。MeCabを使った開発をするための開発環境や形態素の辞書も入れます。
$ sudo apt-get install mecab libmecab-dev mecab-ipadic-utf8 mecab-jumandic-utf8
ここまでやるとMeCabが動くはずなので、動かしてみます。
※実際には僕は別の方法を試した後にこれらのパッケージがあることを知ったので、この通りには試していません。たぶん動くとは思うけれど、動かなかったらごめんなさい。
$ mecab 僕は杉山です。 僕 名詞,代名詞,一般,*,*,*,僕,ボク,ボク は 助詞,係助詞,*,*,*,*,は,ハ,ワ 杉山 名詞,固有名詞,人名,姓,*,*,杉山,スギヤマ,スギヤマ です 助動詞,*,*,*,特殊・デス,基本形,です,デス,デス 。 記号,句点,*,*,*,*,。,。,。 EOS
ちゃんと形態素にわかれて、品詞や読みも表示されました。いい感じ。
mecab-rubyのインストール
つぎはRubyからMeCabを使ってみたいのですが、Ruby用のMeCabインタフェースとなるものを、さらにインストールする必要があります。mecab-rubyというものです。これはapt-getで入るパッケージにはなっていないようなので、tarボールを http://sourceforge.net/projects/mecab/files/mecab-ruby/ から落としてきました。
mecab-ruby-0.98.tar.gz というファイルです。これを解凍してライブラリを作ります。
$ tar xvfz mecab-ruby-0.98.tar.gz $ cd mecab-ruby-0.98 $ ruby extconf.rb $ make
エラーが出ました。
MeCab_wrap.cpp: 関数 ‘VALUE _wrap_DictionaryInfo_filename_get(int, VALUE*, VALUE)’ 内: MeCab_wrap.cpp:2229:5: 警告: 書式が文字列リテラルでは無く、かつ書式引数ではありません [-Wformat-security] MeCab_wrap.cpp: 関数 ‘VALUE _wrap_DictionaryInfo_charset_get(int, VALUE*, VALUE)’ 内: MeCab_wrap.cpp:2253:5: 警告: 書式が文字列リテラルでは無く、かつ書式引数ではありません [-Wformat-security] ……
MeCab_wrap.cppの該当行を見てみると
SWIG_exception_fail(SWIG_ArgError(res1), Ruby_Format_TypeError( "", "mecab_dictionary_info_t *","type", 1, self ));
となっていました。
defineを探っていくと、SWIG_exception_fail()の第2引数は rb_raise(VALUE err, const char *fmt, ...) のfmtになっていくようですが、これが Ruby Format_TypeError() の戻り値であって、文字列リテラルでもないし、書式引数でもないということでしょうか。
自分に優しい僕は、こんなwarningはもちろん無視します。
で、付属のテストスクリプトを動かしてみます。
$ ruby test.rb test.rb:4: invalid multibyte char (US-ASCII) test.rb:4: invalid multibyte char (US-ASCII)
うう……。これはRubyが新しめの1.9.xになのに、test.rbがそれに対応していないからでしょうね。 test.rb の2行目にCoding指定行を挿入します。
#Coding:utf-8
では、再実行。
$ ruby test.rb <internal:lib/rubygems/custom_require>:29:in `require': no such file to load -- MeCab (LoadError) from <internal:lib/rubygems/custom_require>:29:in `require' from test.rb:4:in `<main>'
MeCab.soはカレントディレクトリにあるのですが、それを見ることができていないようです。面倒なので、test.rb の require行を変えました。
require './MeCab'
再々実行。
$ ruby test.rb 0.98 太郎 名詞,固有名詞,人名,名,*,*,太郎,タロウ,タロー は 助詞,係助詞,*,*,*,*,は,ハ,ワ この 連体詞,*,*,*,*,*,この,コノ,コノ 本 名詞,一般,*,*,*,*,本,ホン,ホン を 助詞,格助詞,一般,*,*,*,を,ヲ,ヲ 二 名詞,数,*,*,*,*,二,ニ,ニ 郎 名詞,一般,*,*,*,*,郎,ロウ,ロー を 助詞,格助詞,一般,*,*,*,を,ヲ,ヲ ……
やっと動いた……。ってことで、インストールします。
$ sudo make install
test.rb内のMeCabのパスの記述を元に戻して再々々実行してみましたが、ちゃんと動作しました。よしよし。
解析対象となる文を抽出
現在、得られているツイートは次の形式のファイルで保存してあります。
$ head data/20111214 2011/12/14 12:55:49 P xxxxxxxx こんにちは♪皆さん、風邪に気をつけましょう!"@xxxxxxxx: @xxxxxxxx @xxxxxxxx @xxxxxxxx @xxxxxxxx @xxxxxxxx おはよー(^^)" 2011/12/14 12:55:49 P xxxxxxxx 良い感じ!RT @xxxxxxxx: おっ!!RT @xxxxxxxx: http://t.co/51pNTQ5F デンプンの曲が入ってくるぞ。@xxxxxxxx 2011/12/14 12:55:49 R xxxxxxxx @xxxxxxxx 拗ねちゃいや!花嫁姿見せるから! 2011/12/14 12:55:50 P xxxxxxxx 食後のジュースじゃんけんに初参戦したけど負ける気がしなかった。りこなんじゃないところでの勝負は心に余裕が持てる。 2011/12/14 12:55:50 P xxxxxxxx バス内で若妻を集団痴漢! http://t.co/NrXhzUBn #エロ動画 #アダルト #スマホ #携帯 2011/12/14 12:55:50 R xxxxxxxx @xxxxxxxx 何ぺ?? 2011/12/14 12:55:50 P xxxxxxxx ちょっ!!(^◇^;)RT @xxxxxxxx: @xxxxxxxx いえ、ダブルクォーターパウンダーチーズ2つ重ねです。 2011/12/14 12:55:52 R xxxxxxxx @xxxxxxxx カッコいいからダメです(笑) 2011/12/14 12:55:53 R xxxxxxxx @xxxxxxxx メモリ差? 2011/12/14 12:55:53 P xxxxxxxx 先生やたらめったら褒めてくれるから調子のりそう(笑)
これを処理していきたいのですが、とりあえずツイート本文以外は使いません。また、「@〜」というメンション先アカウントや「#〜」というハッシュタグも無視したいところ。「http〜」というURL記述も削除してしまおうと思います。解析の邪魔になりそうな情報はあらかじめ消してしまうほうが良いと思います。
そのあたりをRubyのスクリプトに入れてもいいのですが、ひとまず次のようにして試してみました。
$ head data/20111214 | awk -F'\t' 'NF==5 {print $5}' | sed 's/[@#][^ ]\+//g' | sed 's/http[^ ]*//g' こんにちは♪皆さん、風邪に気をつけましょう!" おはよー(^^)" 良い感じ!RT おっ!!RT デンプンの曲が入ってくるぞ。@denpunn 拗ねちゃいや!花嫁姿見せるから! 食後のジュースじゃんけんに初参戦したけど負ける気がしなかった。りこなんじゃないところでの勝負は心に余裕が持てる。 バス内で若妻を集団痴漢! 何ぺ?? ちょっ!!(^◇^;)RT いえ、ダブルクォーターパウンダーチーズ2つ重ねです。 カッコいいからダメです(笑) メモリ差? 先生やたらめったら褒めてくれるから調子のりそう(笑)
悪くないです。上の例ではメンションが残っていますが、これは@がいわゆる全角文字ですね。こういったものも除去できますが、こういうことを追求していくとキリがないので、いまはこのままにしておきます。顔文字や「(笑)」なんかも消した方が良いのですけれども。
用途に応じて各種記号や「RT」に続く文章を消すことも必要になりますね。
3日分のログファイルをそれぞれ上記フィルタをかけて、処理対象の文だけにしたファイルにしました。
$ cat data/20111214 | awk -F'\t' 'NF==5 {print $5}'|sed 's/[@#][^ ]\+//g' |sed 's/http[^ ]*//' > tmp20111214 $ cat data/20111215 | awk -F'\t' 'NF==5 {print $5}'|sed 's/[@#][^ ]\+//g' |sed 's/http[^ ]*//' > tmp20111215 $ cat data/20111216 | awk -F'\t' 'NF==5 {print $5}'|sed 's/[@#][^ ]\+//g' |sed 's/http[^ ]*//' > tmp20111216
ツイートから名詞だけを抽出する
これらのファイルを処理していくのですが、まずMeCabで名詞と判定された形態素だけを抽出するということをやってみます。次のmorpher.rbというRubyスクリプトを書きました。
#!/usr/bin/ruby #Coding:utf-8 require 'MeCab' mc = MeCab::Tagger.new('--node-format=%m\t%f[0]\n --eos-format=\tEOS\n') while gets morphs = mc.parse($_).force_encoding("utf-8").split("\n") morphs.each do |morph| morph_inf = morph.split("\t") puts morph_inf[0] if morph_inf[1].chomp == "名詞" end end
もっとRubyっぽくて効率が良くてカッコいいスクリプトが書けたら良いのですが、追求しないことにします。最初はforce_encoding()なしでやってみたのですが、MeCabの解析結果の文字列をRubyがちゃんとUTF-8だと捉えてくれず、うまくいきませんでした。でも、force_encoding()を使わずにうまくいく方法もありそうです。
なお、RubyによるMeCabを扱ったコードを検索すると、parseToNode()というメソッドを使っている方が多いようです。MeCabインスタンスは直前の解析結果を保持していて、ノードとして扱う場合にはそれに依存することになります。その方法は僕の性に合わないので今回は使っていません。
この簡単なスクリプトを使ってツイートから名詞だけを抽出します。
$ cat tmp20111214 | ./morpher.rb > nouns20111214
得られた名詞の頻度を調べる
得られた名詞の出現回数(頻度)を数えて、頻度の多い順に並べてみます。
$ sort nouns20111214 | uniq -c | sort -nr > count_nouns20111214
得られた結果のファイルから、上位10番までの名詞を表示してみます。
$ head count_nouns20111214|cat -n 1 20350 RT 2 19846 ー 3 15534 ん 4 15138 ( 5 14090 の 6 13050 ) 7 9384 さん 8 8080 人 9 7169 笑 10 6873 こと
順位、頻度、名詞そのものの順番で表示しています。想定内ではあったのですが、これではあまり良い情報とは言えません。
こういった感じで、名詞ではあってもあまり情報として美味しくないものはどこかのタイミングで除外する必要があります。また、2番目の「ー」や4番と6番の括弧のような記号も除外したいところです。
「ん」が名詞として現れていたり、「の」も助詞ではなく名詞として解析されたようです。これは元の文によります。ひらがな1文字が本当に名詞であったとしても、あまり情報としては重要ではないので、こういったものも目的に応じて除外して良いと思います。
頻度の多い名詞
頻度順が300番までの名詞から、ある程度意味のありそうなものを手で抽出してみました。
13 5260 私 14 5168 今日 36 2889 今 37 2875 俺 40 2713 自分 42 2683 好き 46 2423 明日 49 2303 時間 67 1769 円 74 1603 仕事 77 1569 大丈夫 79 1524 地震 88 1381 誰 89 1362 うち 90 1353 みんな 91 1337 最近 94 1283 話 103 1210 フォロー 105 1207 ミタ 106 1191 なに 107 1176 僕 108 1159 日本 110 1130 お願い 122 1025 感じ 123 1012 わたし 125 1005 顔 126 1005 一緒 129 982 先生 132 941 いま 133 925 ところ 134 924 本 138 913 君 139 906 バイト 141 898 楽しみ 143 881 店 144 880 手 145 860 男 146 851 クリスマス 148 846 流星 149 840 頭 150 837 情報 156 810 友達 158 806 絶対 159 806 意味 163 795 世界 168 770 無理 169 767 夜 174 759 ここ 177 753 ツイート 178 745 昨日 179 736 風呂 180 736 声 181 735 あたし 182 734 曲 185 715 メール 186 714 写真 187 712 問題 188 710 東京 189 710 ゲーム 193 695 あなた 194 690 マジ 199 671 更新 200 670 定期 201 668 電車 202 664 一番 203 664 こちら 204 661 今年 205 660 女子 206 658 普通 207 658 希望 208 658 学校 211 654 ブログ 213 646 駅 214 646 まじ 215 645 ライブ 216 642 予定 217 642 お前 218 641 大好き 219 640 気持ち 222 635 県 223 633 発売 224 630 歳 228 613 名前 229 609 女 230 608 性 234 593 震度 235 592 帰宅 236 591 心 238 588 ダメ 239 586 数 240 584 以上 241 583 久しぶり 243 582 来年 245 580 ご飯 246 576 音 248 575 ネイマール 249 573 本日 254 568 勉強 255 560 そこ 259 551 人間 260 547 無料 262 546 さっき 263 545 韓国 264 545 金 265 544 プレゼント 268 535 最後 269 530 朝 270 530 お腹 273 523 大阪 275 521 会社 276 520 言葉 277 520 映画 281 515 拡散 282 515 ポイント 284 512 子供 285 509 電話 288 506 全部 291 505 動画 294 501 部屋 296 497 幸せ 297 497 今度 298 497 いつ 300 493 確か
105番の「ミタ」はドラマ「家政婦のミタ」の話題によるものでしょう。248番の「ネイマール」もブラジルから来日している注目のサッカー選手ですね。いまはクリスマス前なので146番に「クリスマス」が入っているのもうなずけます。
単純な名詞抽出のあとに
上記の名詞の上から5つは「私」「今日」「今」「俺」「自分」です。こんな名詞は毎日常に上位にあるはずです。もしトレンドワードなんかを調べたかったとすると、これらの単語は不要ですよね。そんなときは、頻度値の変化を見るべきです。時系列の頻度値の微分してもいいし、別の方法もいろいろあるのでしょう。
複合語
たとえば「福島第一原発がたいへんだ」という文があると、「福島第一原発」で1つの固有名詞として扱いたかったりするのですが、辞書になければそううまく解析できません。「福島第一原発」が「福島」「第」「一」「原発」と、4つの形態素として解析されたりします。ほかにも「プロ野球」が話題の時期に「プロ」がトレンドワードになっても意味不明ですし。
こういったいわゆる複合名詞をうまく扱うには、辞書に登録したり、もしくは解析後に連結させたりします。辞書登録するにしても連結させるにしても、そこにはいろいろなワザがあると思います。知らない単語だからこそ辞書になかったりするのに、どうやればいいのか。すべて人手でやるのはたいへんなので統計的な手法が必要になってきますよね、たぶん。
布団を買った
全然関係ないんですけど、布団を買いました。昨日届きました。
これまでうちには布団がなかったのです。秋までは羽毛布団があったのですが、十数年使って汚かったので捨ててしまいました。
昨日までは3つ折りマットレスの上に敷きパッド、掛け布団がないのでタオルケット、毛布を掛け、さらに夏用寝袋を開いて掛けていました。それでこの冬は越せそうだと思っていたし、いざとなったら羽毛の寝袋もあるので生きてはいけると思ったのですが、つい楽天のセールの勢いに負けました。
買うなら羽毛布団にしようと思っていたのですが、羽毛は洗うとなかなか乾かないし、湿気もなかなか取れにくいのがネックです。そこで、今回はプリマロフトという化繊のものにチャレンジしてみました。旧タイプのやつは1000円くらい安いようですが、新タイプのほうが暖かいようなので、新タイプにしてみました。
届いたものは思ったより薄かったのですが、その薄い見た目を考えても軽く感じました。毛布とその掛け布団で一晩過ごしてみましたが、だいぶ暖かくて熟睡です。今回の判断はアタリでした。
ちょっと色気を出してアフィリエイトリンクを貼っておきます。;p
【ポイント10倍】【送料無料】人工羽毛布団 シングル 掛け布団 人工羽毛人工羽毛布団 シングル ... |