MeCab, CaboCha で楽々自然言語処理 (Mac + Perl)
これ何
Perl で MeCab や CaboCha を使う際の適当にメモ
MeCab に関しては情報が多いが CaboCha はあまり無いので Mac + Perl でしたい方は気持ち参考にして頂けたらと思う
特に自然言語処理の研究がメインではないが、文書構造など適度に取得して使いたい分野
全く触れた事無い人でも便利ライブラリを使う事で以下のように色々遊べる
書く人が書けば以下のような適当なのでもブクマ稼げる
- 例
- Twitter から tweet を取得し、MeCab で形容詞抽出語に公開資源/日本語評価極性辞書 - 東北大学 乾・岡﨑研究室を使ってハッシュタグ毎の感性分析を行う
- 注目ハッシュタグの中からハッピー度合い計算して取り上げるようなサービス
- MeCab で名詞のみ抽出し、BagOfWords としてベイジアンフィルタにかけてスパム判定,LDA 使ってトピック推定
- CaboCha で名詞にかかる形容詞を抽出し、名詞毎の極性を算出
- etc...
MeCab
文を入力に、単語を分割して名詞が、形容詞が、といった結果を出す形態素解析器
- インストール
- デフォルトでutf-8の辞書が入る
brew install mecab mecab-ipadic
cpanm --interactive Text::MeCab
#!/usr/bin/env perl use v5.14; use strict; use warnings; use utf8; use Text::MeCab; use Encode qw/decode_utf8 encode_utf8/; my $text = "すもももももももものうち"; my $mecab = Text::MeCab->new; my $node = $mecab->parse($text); while($node) { # コード内ではUTF-8フラグの立っている文字列を扱う my $surface = decode_utf8 $node->surface; # すもも my $feature = decode_utf8 $node->feature; # 名詞,一般,*,*,*,*,すもも,スモモ,スモモ # 出力する際はUTF-8フラグを取り除く say encode_utf8 $surface; say encode_utf8 $feature; $node = $node->next; } __END__
UTF-8フラグについては、Perl で utf8 化けしたときにどうしたらいいか - blog.64p.org
入り口で decode して、内部ではすべて flagged utf8 で扱い、出口で encode する。これがすべてです!とにかくこの基本方針をまもっていれば幸せになれます。
プログラム中では `use utf8` で内部文字列はUTF-8フラグを立てたものを使い、入り口で decode 、出口で encode
で、Text::MeCab は Devel::Peek すると分かるが、 UTF-8 フラグの立ってない結果を返すので、外から来たものとして扱い、中で用いる際には decode してから使う。出力するならまた encode する
注意点として、例えば TFIDF とか計算する際に日本語を hash の key にしたいが、UTF-8 フラグの立った文字は key に出来ないので注意
また、通常の辞書だけでなく Wikipedia や はてなキーワード といったものを扱う事もできる
昔ので Macports とか使ってるけど一応参考記事はこっち Mecab dictionary, with cmecab-java - krrrr38.com
Perl から固有辞書を使う際は `$mecab = Text::MeCab->new({ userdic => 'mydic' })` とか
CaboCha
文を入力に、「A が B した。」に対して 「A → B」といった結果を出す係り受け解析器
- インストール
- mecab に依存した CaboCha が入る
brew cabocha
cabocha --version
CPAN に CaboCha のラッパーライブラリは存在しないが、元々用意されているのでcabocha - Yet Another Japanese Dependency Structure Analyzer - Google Project Hostingから version の等しい tar.bz2 とか落として解凍
cd cabocha-x.xx/perl
cpanm .
動作確認
perl test.pl
形態素解析結果はも取れたりするのだが、上記のようなものが取れたら満足なのではないかと思う
特に Document など無いので必要そうなのだけ考える
中に含まれる CaboCha.pm を見れば良いのだが、依存クラスとして以下のようなものがある
- CaboCha::Parser
- 文を入力に Parser で parse する事で結果 (Tree) が得られる
- CaboCha::Tree
- Parser で得られた結果。係り受け構造は test.pl を見て分かるが木のようになる。
- CaboCha::Chunk
- 係り受け構造の文節単位
- 例:"すももも" - "ももも" - "ももの" - "うち" (chunk size = 4)
- CaboCha::Token
- 形態素解析結果の最小単位
- 例 : "「すもも」「も」" - "「もも」「も」" - "「もも」「の」" - "「うち」" (token size = 7)
- chunk といった文節の中に語がいくつ含まれるといった情報も保持される
#!/usr/bin/env perl use v5.14; use strict; use warnings; use utf8; use CaboCha; my $text = "すもももももももものうち"; my $parser = CaboCha::Parser->new; my $tree = $parser->parse($text); my $chunk_number = 0; for (my $i = 0; $i < $tree->chunk_size; ++$i) { my $chunk = $tree->chunk($i); # chunk 番号は数え上げる。係り受け先は link で取得 say sprintf("chunk %d is following chunk %d", $chunk_number++, $chunk->{link}); # token_size で chunk に含まれる token の数が取れる # token_pos で chunk に含まれる token の先頭の index が取れる for(my $j = 0; $j < $chunk->{token_size}; ++$j){ my $token = $tree->token($chunk->{token_pos} + $j); # token # ここで得られる値も UTF-8 は立っていないので注意 say "\t" . $token->{surface} . " : " . $token->{feature}; } } __END__
Token から Chunk を得る事も可能なので、先に形態素解析結果を見た後に名詞がどの文節にかかるか確認したいなどといった場合には、以下のようにしても良い
UTF-8 の立った文字列は decode した上で処理を行うのを忘れないよう
for (my $i = 0; $i < $tree->token_size; ++$i) { my $token = $tree->token($i); my $feature = decode_utf8($token->{feature}); if ($feature =~ /^名詞/) { my $chunk = $token->{chunk}; say $token->{surface} . " is following chunk " . $chunk->{link}; } }
`$chunk->{link}` が -1 になると、文が終わりとなる
"。" などで区切られた文に対しても CaboCha は係り受け構造があると認めるので、一応気にしておくべきな気がする
一応ではあるが Cabocha.pm に対して、 Token の `*swig_surface_get` といった記述に対して `$token->{surface}` や `$token->swig_surface_get()` がそのまま扱える