読者です 読者をやめる 読者になる 読者になる

Splunkを利用したテキストマイニングもどき

NLP 統計学

さて、前回の記事で、PerlからLTSV形式のフォーマットを扱う方法を書いた。

http://rn.hatenablog.com/entry/2013/12/07/012621

そのとき、自然言語処理の分野での適用をぼんやり考えていて、単語とか品詞とか簡単に集計できる仕組みがあると役立つかなと思った。現状、こういったことを簡単にやろうと思っても、それっぽい専用ソフトが必要なので、やりにくいかなと思う。

そこで、Jumanで抽出した形態素解析情報をLTSV形式で表現し、Splunkでビジュアルに扱う方法について書いてみたいと思う。現状、かなり試行錯誤だし、ベストプラクティスを発見できていないが、せっかく試したので書いてみる。というのも、Splunkをテキストマイニングっぽく使うというのは、あまり聞いたことがないからだ。

さて、Splunkというソフトを知っているだろうか?私も最近知ったが、主にログを解析するためのソフトである。日本だと、大手SIerが積極的に扱っている。ただし、大規模なデータを扱うのでなければ、フリーでも利用することができる。

例えば、日本語のホームページは以下にある。

http://ja.splunk.com/

右上にあるダウンロードボタンからダウンロードすることができる。プラットフォームは、WindowsとLinuxとMacなどがある。今回は、Cent OSを利用したので、32bitのLinux版をダウンロードした。ソースからでもrpmからでもどちらでもインストールすることができる。

データとしては、日本語のWikipediaの情報を利用した。Wikipediaからのテキストの抽出については、以下を参照してください。

http://rn.hatenablog.com/entry/2012/09/09/003001

まず、結論からすると、結果の画面は以下のようになった。

f:id:ryokkie:20131209022210p:plain

形態素をテキストごとに表示している。任意のキーワードで検索できるし、その形態素解析結果も見やすいのではないだろうか。

また、以下ののように、もう少し視覚的に、どの品詞がどのぐらい使われているか?ということも見ることができる。

f:id:ryokkie:20131209022223p:plain

さらに、上位10件を表示するコマンドを利用すると、グラフも一発で作成できる。

f:id:ryokkie:20131209022235p:plain

次に、どうやってこんな処理をSplunkで行うか?について説明しておく。私は、Jumanがけっこう好きなので、Jumanを利用したが、別にMeCabでもKyTeaでも問題ない。Splunk自体は、DWHと可視化がセットになっているだけなので、解析器自体はなんでも良い。

まず、Jumanを使って、解析結果を以下のようなLTSV形式にしておく。

base_file_name:txt/00027.txt    title:自然言語  line_no:3       str:「自然言語」という語は特に数式やプログラミング言語など人工的に定義された形式言語・人工言語に対比させる必要がある場合にこ う呼ばれる。    mrph_000_midasi:「      mrph_000_yomi:「        mrph_000_genkei:「      mrph_000_hinsi:特殊     mrph_000_hinsi_id:1     mrph_000_bunrui:括弧始  mrph_000_bunrui_id:3    mrph_000_katuyou1:*  mrph_000_katuyou1_id:0  mrph_000_katuyou2:*     mrph_000_katuyou2_id:0  mrph_000_imis:NIL       mrph_001_midasi:自然    mrph_001_yomi:しぜん    mrph_001_genkei:自然    mrph_001_hinsi:副詞  mrph_001_hinsi_id:8     mrph_001_bunrui:*       mrph_001_bunrui_id:0    mrph_001_katuyou1:*     mrph_001_katuyou1_id:0  mrph_001_katuyou2:*     mrph_001_katuyou2_id:0  mrph_001_imis:"代表表記:自然/しぜん 修飾(ト格)"    mrph_002_midasi:言語    mrph_002_yomi:げんご    mrph_002_genkei:言語    mrph_002_hinsi:名詞     mrph_002_hinsi_id:6     mrph_002_bunrui:普通 名詞    mrph_002_bunrui_id:1    mrph_002_katuyou1:*     mrph_002_katuyou1_id:0  mrph_002_katuyou2:*     mrph_002_katuyou2_id:0  mrph_002_imis:"代表表記:言語/げんご カテゴリ:抽象物"    mrph_003_midasi:」   mrph_003_yomi:」        mrph_003_genkei:」      mrph_003_hinsi:特殊     mrph_003_hinsi_id:1     mrph_003_bunrui:括弧終  mrph_003_bunrui_id:4    mrph_003_katuyou1:*     mrph_003_katuyou1_id:0       mrph_003_katuyou2:*     mrph_003_katuyou2_id:0  mrph_003_imis:NIL       mrph_004_midasi:と      mrph_004_yomi:と        mrph_004_genkei:と      mrph_004_hinsi:助詞  mrph_004_hinsi_id:9     mrph_004_bunrui:格助詞  mrph_004_bunrui_id:1    mrph_004_katuyou1:*     mrph_004_katuyou1_id:0  mrph_004_katuyou2:*     mrph_004_katuyou2_id:0  mrph_004_imis:NIL    mrph_005_midasi:いう    mrph_005_yomi:いう      mrph_005_genkei:いう    mrph_005_hinsi:動詞     mrph_005_hinsi_id:2     mrph_005_bunrui:*       mrph_005_bunrui_id:0    mrph_005_katuyou1:子 音動詞ワ行      mrph_005_katuyou1_id:12 mrph_005_katuyou2:基本形        mrph_005_katuyou2_id:2  mrph_005_imis:"代表表記:言う/いう 補文ト"       mrph_006_midasi:語      mrph_006_yomi:ご     mrph_006_genkei:語      mrph_006_hinsi:名詞     mrph_006_hinsi_id:6     mrph_006_bunrui:普通名詞        mrph_006_bunrui_id:1    mrph_006_katuyou1:*     mrph_006_katuyou1_id:0  mrph_006_katuyou2:*  mrph_006_katuyou2_id:0  mrph_006_imis:"代表表記:語/ご 漢字読み:音 カテゴリ:抽象物"      mrph_007_midasi:は      mrph_007_yomi:は        mrph_007_genkei:は      mrph_007_hinsi:助詞  mrph_007_hinsi_id:9     mrph_007_bunrui:副助詞  mrph_007_bunrui_id:2    mrph_007_katuyou1:*     mrph_007_katuyou1_id:0  mrph_007_katuyou2:*     mrph_007_katuyou2_id:0  mrph_007_imis:NIL    mrph_008_midasi:特に    mrph_008_yomi:とくに    mrph_008_genkei:特に    mrph_008_hinsi:副詞     mrph_008_hinsi_id:8     mrph_008_bunrui:*       mrph_008_bunrui_id:0    mrph_008_katuyou1:*  mrph_008_katuyou1_id:0  mrph_008_katuyou2:*     mrph_008_katuyou2_id:0  mrph_008_imis:"代表表記:特に/とくに 用言弱修飾" mrph_009_midasi:数式    mrph_009_yomi:すうしき  mrph_009_genkei:数式 mrph_009_hinsi:名詞     mrph_009_hinsi_id:6     mrph_009_bunrui:普通名詞        mrph_009_bunrui_id:1    mrph_009_katuyou1:*     mrph_009_katuyou1_id:0  mrph_009_katuyou2:*     mrph_009_katuyou2_id:0       mrph_009_imis:"代表表記:数式/すうしき カテゴリ:抽象物 ドメイン:教育・学習"      mrph_010_midasi:や      mrph_010_yomi:や        mrph_010_genkei:や      mrph_010_hinsi:助詞  mrph_010_hinsi_id:9     mrph_010_bunrui:接続助詞        mrph_010_bunrui_id:3    mrph_010_katuyou1:*     mrph_010_katuyou1_id:0  mrph_010_katuyou2:*     mrph_010_katuyou2_id:0  mrph_010_imis:NIL    mrph_011_midasi:プログラミング  mrph_011_yomi:ぷろぐらみんぐ    mrph_011_genkei:プログラミング  mrph_011_hinsi:名詞     mrph_011_hinsi_id:6     mrph_011_bunrui:サ変名詞        mrph_011_bunrui_id:2 mrph_011_katuyou1:*     mrph_011_katuyou1_id:0  mrph_011_katuyou2:*     mrph_011_katuyou2_id:0  mrph_011_imis:"代表表記:プログラミング/ぷろぐらみんぐ カテゴリ:抽象物 ドメイ ン:科学・技術"  mrph_012_midasi:言語    mrph_012_yomi:げんご    mrph_012_genkei:言語    mrph_012_hinsi:名詞     mrph_012_hinsi_id:6     mrph_012_bunrui:普通名詞        mrph_012_bunrui_id:1 mrph_012_katuyou1:*     mrph_012_katuyou1_id:0  mrph_012_katuyou2:*     mrph_012_katuyou2_id:0  mrph_012_imis:"代表表記:言語/げんご カテゴリ:抽象物"    mrph_013_midasi:など    mrph_013_yomi:など   mrph_013_genkei:など    mrph_013_hinsi:助詞     mrph_013_hinsi_id:9     mrph_013_bunrui:副助詞  mrph_013_bunrui_id:2    mrph_013_katuyou1:*     mrph_013_katuyou1_id:0  mrph_013_katuyou2:*  mrph_013_katuyou2_id:0  mrph_013_imis:NIL       mrph_014_midasi:人工    mrph_014_yomi:じんこう  mrph_014_genkei:人工    mrph_014_hinsi:名詞     mrph_014_hinsi_id:6     mrph_014_bunrui:普通名詞     mrph_014_bunrui_id:1    mrph_014_katuyou1:*     mrph_014_katuyou1_id:0  mrph_014_katuyou2:*     mrph_014_katuyou2_id:0  mrph_014_imis:"代表表記:人工/じんこう カテゴリ:抽象物"       mrph_015_midasi:的に    mrph_015_yomi:てきに    mrph_015_genkei:的だ    mrph_015_hinsi:接尾辞   mrph_015_hinsi_id:14    mrph_015_bunrui:形容詞性名詞接尾辞      mrph_015_bunrui_id:6 mrph_015_katuyou1:ナ形容詞      mrph_015_katuyou1_id:21 mrph_015_katuyou2:ダ列基本連用形        mrph_015_katuyou2_id:7  mrph_015_imis:"代表表記:的だ/てきだ 準内容語 カテゴリ:抽象物"   mrph_016_midasi:定義 mrph_016_yomi:ていぎ    mrph_016_genkei:定義    mrph_016_hinsi:名詞     mrph_016_hinsi_id:6     mrph_016_bunrui:サ変名詞        mrph_016_bunrui_id:2    mrph_016_katuyou1:*  mrph_016_katuyou1_id:0  mrph_016_katuyou2:*     mrph_016_katuyou2_id:0  mrph_016_imis:"代表表記:定義/ていぎ カテゴリ:抽象物 ドメイン:科学・技術"        mrph_017_midasi:さ      mrph_017_yomi:さ     mrph_017_genkei:する    mrph_017_hinsi:動詞     mrph_017_hinsi_id:2     mrph_017_bunrui:*       mrph_017_bunrui_id:0    mrph_017_katuyou1:サ変動詞      mrph_017_katuyou1_id:16 mrph_017_katuyou2:未然形     mrph_017_katuyou2_id:3  mrph_017_imis:"代表表記:する/する 付属動詞候補(基本) 自他動詞:自:成る/なる"   mrph_018_midasi:れた    mrph_018_yomi:れた      mrph_018_genkei:れる mrph_018_hinsi:接尾辞   mrph_018_hinsi_id:14    mrph_018_bunrui:動詞性接尾辞    mrph_018_bunrui_id:7    mrph_018_katuyou1:母音動詞      mrph_018_katuyou1_id:1  mrph_018_katuyou2:タ 形      mrph_018_katuyou2_id:10 mrph_018_imis:"代表表記:れる/れる"      mrph_019_midasi:形式    mrph_019_yomi:けいしき  mrph_019_genkei:形式    mrph_019_hinsi:名詞     mrph_019_hinsi_id:6  mrph_019_bunrui:普通名詞        mrph_019_bunrui_id:1    mrph_019_katuyou1:*     mrph_019_katuyou1_id:0  mrph_019_katuyou2:*     mrph_019_katuyou2_id:0  mrph_019_imis:"代表表記:形式/けいしき カテゴリ:抽象物"       mrph_020_midasi:言語    mrph_020_yomi:げんご    mrph_020_genkei:言語    mrph_020_hinsi:名詞     mrph_020_hinsi_id:6     mrph_020_bunrui:普通名詞        mrph_020_bunrui_id:1 mrph_020_katuyou1:*     mrph_020_katuyou1_id:0  mrph_020_katuyou2:*     mrph_020_katuyou2_id:0  mrph_020_imis:"代表表記:言語/げんご カテゴリ:抽象物"    mrph_021_midasi:・      mrph_021_yomi:・     mrph_021_genkei:・      mrph_021_hinsi:特殊     mrph_021_hinsi_id:1     mrph_021_bunrui:記号    mrph_021_bunrui_id:5    mrph_021_katuyou1:*     mrph_021_katuyou1_id:0  mrph_021_katuyou2:*  mrph_021_katuyou2_id:0  mrph_021_imis:NIL       mrph_022_midasi:人工    mrph_022_yomi:じんこう  mrph_022_genkei:人工    mrph_022_hinsi:名詞     mrph_022_hinsi_id:6     mrph_022_bunrui:普通名詞     mrph_022_bunrui_id:1    mrph_022_katuyou1:*     mrph_022_katuyou1_id:0  mrph_022_katuyou2:*     mrph_022_katuyou2_id:0  mrph_022_imis:"代表表記:人工/じんこう カテゴ リ:抽象物"      mrph_023_midasi:言語    mrph_023_yomi:げんご    mrph_023_genkei:言語    mrph_023_hinsi:名詞     mrph_023_hinsi_id:6     mrph_023_bunrui:普通名詞        mrph_023_bunrui_id:1 mrph_023_katuyou1:*     mrph_023_katuyou1_id:0  mrph_023_katuyou2:*     mrph_023_katuyou2_id:0  mrph_023_imis:"代表表記:言語/げんご カテゴリ:抽象物"    mrph_024_midasi:に      mrph_024_yomi:に     mrph_024_genkei:に      mrph_024_hinsi:助詞     mrph_024_hinsi_id:9     mrph_024_bunrui:格助詞  mrph_024_bunrui_id:1    mrph_024_katuyou1:*     mrph_024_katuyou1_id:0  mrph_024_katuyou2:*  mrph_024_katuyou2_id:0  mrph_024_imis:NIL       mrph_025_midasi:対比    mrph_025_yomi:たいひ    mrph_025_genkei:対比    mrph_025_hinsi:名詞     mrph_025_hinsi_id:6     mrph_025_bunrui:サ変名詞     mrph_025_bunrui_id:2    mrph_025_katuyou1:*     mrph_025_katuyou1_id:0  mrph_025_katuyou2:*     mrph_025_katuyou2_id:0  mrph_025_imis:"代表表記:対比/たいひ カテゴリ:抽象物" mrph_026_midasi:さ      mrph_026_yomi:さ        mrph_026_genkei:する    mrph_026_hinsi:動詞     mrph_026_hinsi_id:2     mrph_026_bunrui:*       mrph_026_bunrui_id:0    mrph_026_katuyou1:サ 変動詞  mrph_026_katuyou1_id:16 mrph_026_katuyou2:未然形        mrph_026_katuyou2_id:3  mrph_026_imis:"代表表記:する/する 付属動詞候補(基本) 自他動詞:自:成る/なる"   mrph_027_midasi:せる mrph_027_yomi:せる      mrph_027_genkei:せる    mrph_027_hinsi:接尾辞   mrph_027_hinsi_id:14    mrph_027_bunrui:動詞性接尾辞    mrph_027_bunrui_id:7    mrph_027_katuyou1:母音動詞      mrph_027_katuyou1_id:1       mrph_027_katuyou2:基本形        mrph_027_katuyou2_id:2  mrph_027_imis:"代表表記:せる/せる"      mrph_028_midasi:必要    mrph_028_yomi:ひつよう  mrph_028_genkei:必要 だ      mrph_028_hinsi:形容詞   mrph_028_hinsi_id:3     mrph_028_bunrui:*       mrph_028_bunrui_id:0    mrph_028_katuyou1:ナノ形容詞    mrph_028_katuyou1_id:22 mrph_028_katuyou2:語幹  mrph_028_katuyou2_id:1       mrph_028_imis:"代表表記:必要だ/ひつようだ 反義:形容詞:不要だ/ふようだ"  mrph_029_midasi:が      mrph_029_yomi:が        mrph_029_genkei:が      mrph_029_hinsi:助詞  mrph_029_hinsi_id:9     mrph_029_bunrui:格助詞  mrph_029_bunrui_id:1    mrph_029_katuyou1:*     mrph_029_katuyou1_id:0  mrph_029_katuyou2:*     mrph_029_katuyou2_id:0  mrph_029_imis:NIL    mrph_030_midasi:ある    mrph_030_yomi:ある      mrph_030_genkei:ある    mrph_030_hinsi:動詞     mrph_030_hinsi_id:2     mrph_030_bunrui:*       mrph_030_bunrui_id:0    mrph_030_katuyou1:子 音動詞ラ行      mrph_030_katuyou1_id:10 mrph_030_katuyou2:基本形        mrph_030_katuyou2_id:2  mrph_030_imis:"代表表記:有る/ある 補文ト 反義:形容詞:無い/ない" mrph_031_midasi:場合    mrph_031_yomi:ばあい mrph_031_genkei:場合    mrph_031_hinsi:名詞     mrph_031_hinsi_id:6     mrph_031_bunrui:副詞的名詞      mrph_031_bunrui_id:9    mrph_031_katuyou1:*     mrph_031_katuyou1_id:0       mrph_031_katuyou2:*     mrph_031_katuyou2_id:0  mrph_031_imis:"代表表記:場合/ばあい"    mrph_032_midasi:に      mrph_032_yomi:に        mrph_032_genkei:に      mrph_032_hinsi:助詞  mrph_032_hinsi_id:9     mrph_032_bunrui:格助詞  mrph_032_bunrui_id:1    mrph_032_katuyou1:*     mrph_032_katuyou1_id:0  mrph_032_katuyou2:*     mrph_032_katuyou2_id:0  mrph_032_imis:NIL    mrph_033_midasi:こう    mrph_033_yomi:こう      mrph_033_genkei:こう    mrph_033_hinsi:指示詞   mrph_033_hinsi_id:7     mrph_033_bunrui:副詞形態指示詞  mrph_033_bunrui_id:3    mrph_033_katuyou1:*  mrph_033_katuyou1_id:0  mrph_033_katuyou2:*     mrph_033_katuyou2_id:0  mrph_033_imis:NIL       mrph_034_midasi:呼ば    mrph_034_yomi:よば      mrph_034_genkei:呼ぶ    mrph_034_hinsi:動詞  mrph_034_hinsi_id:2     mrph_034_bunrui:*       mrph_034_bunrui_id:0    mrph_034_katuyou1:子音動詞バ行  mrph_034_katuyou1_id:8  mrph_034_katuyou2:未然形        mrph_034_katuyou2_id:3       mrph_034_imis:"代表表記:呼ぶ/よぶ"      mrph_035_midasi:れる    mrph_035_yomi:れる      mrph_035_genkei:れる    mrph_035_hinsi:接尾辞   mrph_035_hinsi_id:14    mrph_035_bunrui:動詞 性接尾辞        mrph_035_bunrui_id:7    mrph_035_katuyou1:母音動詞      mrph_035_katuyou1_id:1  mrph_035_katuyou2:基本形        mrph_035_katuyou2_id:2  mrph_035_imis:"代表表記:れる/れる"   mrph_036_midasi:。      mrph_036_yomi:。        mrph_036_genkei:。      mrph_036_hinsi:特殊     mrph_036_hinsi_id:1     mrph_036_bunrui:句点    mrph_036_bunrui_id:1    mrph_036_katuyou1:*  mrph_036_katuyou1_id:0  mrph_036_katuyou2:*     mrph_036_katuyou2_id:0  mrph_036_imis:NIL

ちなみに、PerlからJumanを利用する場合は、Juman.pmを利用するのが便利である。それについては、別の記事で書く。

さて、こんな感じでLTSV形式のフォーマットを用意したら、Splunkで読み込むだけである。ただし、Splunkは、LTSV形式のファイルを読み込むことができないので、自分で解析フォーマットを用意する。解析フォーマットは、以下を参考にした。

https://gist.github.com/takscape/4736182

ただし、このままだと、genkeiとかがすべて分かれたものしかできないので、マージしたファセット項目を作成した方が良い。結局、以下のようにする。

# props.conf
[ltsv]
NO_BINARY_CHECK = 1
REPORT-ltsv = ltsv-extractions
REPORT-genkei = jgenkei-extractions
REPORT-hinsi = jhinsi-extractions
REPORT-bunrui = jbunrui-extractions
SHOULD_LINEMERGE = false
TIME_FORMAT = %d/%b/%Y:%H:%M:%S %z
TIME_PREFIX = time:
pulldown_type = 1

# transforms.conf
[ltsv-extractions]
REGEX = (?:^|\t)([0-9A-Za-z_.-]+):([^\t]*)(?:\t|$)
FORMAT = $1::$2
KEEP_EMPTY_VALS = true
CLEAN_KEYS = 0

[jgenkei-extractions]
REGEX = (?:^|\t)(mrph_[0-9]+_genkei):([^\t]*)(?:\t|$)
FORMAT = genkei::$2
REPEAT_MATCH = true
KEEP_EMPTY_VALS = true
CLEAN_KEYS = 0
MV_ADD = 1

[jhinsi-extractions]
REGEX = (?:^|\t)(mrph_[0-9]+_hinsi):([^\t]*)(?:\t|$)
FORMAT = hinsi::$2
REPEAT_MATCH = true
KEEP_EMPTY_VALS = true
CLEAN_KEYS = 0
MV_ADD = 1

[jbunrui-extractions]
REGEX = (?:^|\t)(mrph_[0-9]+_bunrui):([^\t]*)(?:\t|$)
FORMAT = bunrui::$2
REPEAT_MATCH = true
KEEP_EMPTY_VALS = true
CLEAN_KEYS = 0
MV_ADD = 1

これを、以下のフォルダの2つのファイル追加する。なければ、ファイルを作成する。

/opt/splunk/etc/system/local/props.conf
/opt/splunk/etc/system/local/transforms.conf

これで、あとは、LTSV形式にしたWikipediaのデータを読み込むとSplunkの機能で検索したり、集計したり、グラフ作ったりできるようになる。ちなみに、Splunkは、UnixコマンドとSQLを足して2で割ったような操作性であり、そこにstatsコマンドという統計処理用のコマンドで機能を強化している。コマンドリファレンスは、以下にあるので、参考にしてみてください。

http://docs.splunk.com/images/7/78/SearchReference_JA_502.pdf

Splunkの本来の用途であるログ解析から離れて、テキストマイニングもどきに強引に適用してみるということをやってみた。今回は、Wikipediaのデータでやってみたが、時系列が重要なデータだとより良いと思う。というのも、Splunk自体は、時刻を自動でキーにして、時系列の変化を自動でグラフ化してくれるからだ。それを考えると、Twitterなどのデータの方がもっと有益かもしれない。