2011年5月アーカイブ

非常に色々と応用が利きそうで面白かったので自分用のメモ。
昔の専攻がらみで焼けぼっくいに火が付きそう。

HadoopのMapReduceとPythonとmecabを組み合わせてテキストマイニングの取っ掛かりのお話。
条件としては

  • 分散のHadoop環境が構築できていること
  • データノードでpythonが正常に動くこと
  • データノードにmecabがインストールされていること。
です。

Hadoop構築はHadoopのドキュメントを参照しました。
Hadoopで動くPythonのMapReduce環境はこのblogを参照しました。
mecabはmecabの公式ドキュメントを参照しました。
環境構築の話を書くと長くなるので端折ります。

実行したmapperが以下のスクリプト
mapper.py

#!/usr/local/bin/python
# -*- coding: utf-8 -*-
 
import sys
import MeCab
 
# input comes from STDIN (standard input)
m = MeCab.Tagger("-Ogoso")

for line in sys.stdin:
# 行頭と行末の空白を取り除く
line = line.strip()
# 行を単語に分割する
line = m.parse(line)
words = line.split()
# カウンターを上げる
for word in words:
print '%s\t%s' % (word, 1)
# STDOUT (標準出力)に結果を書き込む;
# ここで出力したものはReduce(つまりrecuder.py)での
# 入力になる
#
# タブ文字での分割; 単語の出現回数は 1


 


単純に日本語TEXTを分かち書きしてCountして標準出力に。

実行したreducerは以下のスクリプト
reducer.py



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

from operator import itemgetter
import sys

# 単語の出現回数のマップ
word2count = {}

# 入力はSTDIN
for line in sys.stdin:
# 行頭と行末の空白文字を除去
line = line.strip()

# mapper.pyの出力をパースする
word, count = line.split('\t', 1)
# 回数を文字列から数字に変換
try:
count = int(count)
word2count[word] = word2count.get(word, 0) + count
except ValueError:
# 回数が数字でなければ
# こっそり、この行はなかったことにして捨て去る
pass

# 単語をアスキーソートする
#
# この処理は必要ないが、オフィシャルHadoopの単語の
# カウントサンプルコードの最終出力に似せるために行う。
sorted_word2count = sorted(word2count.items(), key=itemgetter(1))

# STDOUT (標準出力)に結果を書き込む
for word, count in sorted_word2count:
print '%s\t%s'% (word, count)

 


単純にCount数を積算してソートして標準出力に。

単語出力回数順にソートをしています。


これをhadoopコマンドで実行します。


/usr/local/hadoop/bin/hadoop \
jar /usr/local/hadoop/mapred/contrib/streaming/hadoop-0.21.0-streaming.jar \
-mapper /home/hadoop/mapper.py \
-reducer /home/hadoop/reduce.py \
-input /user/hadoop/matome \
-output /user/hadoop/output

約2分強で60MB程の日本語テキストの解析が終了。

昔(10年前)は数ヶ月かけていたのに......。



結果の抜粋はこんな感じ。頻出単語上位です。


を 371190
て 393814
は 426790
に 433759
た 473274
。 477822
の 633713
、 775162

やっぱり「て」、「に」、「を」、「は」が多いんですよね。

これはこれで面白かったのですが、動詞系は活用があるので別カウントされてしまいます。これもつまらないなと思ったのでmecabの設定に手を入れてみました。



/usr/local/lib/mecab/dic/naist-jdic/dicrc

に以下の設定を追記しました。語素の部分のみ出力する設定です。


; goso
node-format-goso = %pS%f[6]\n
unk-format-goso = %M
eos-format-goso = \n

これで活用を無視できるようになります。

てにをはの強さは変わらないので途中の抜粋としては

思う 16754

とか

言う 18065

とかの強さですかねぇ。

てにをはの出現頻度は桁違いですが。


結構簡単にできたのでこれを応用していけば結構面白いことできるかなと思います。応用方法を少し考えてみようかなと。


ウェブページ