MeCabの制約付き解析機能を試す

MeCabに制約付き解析(部分解析)という機能があるのでそのメモです。
参考: 制約付き解析(部分解析)

入力文の一部の形態素情報が既知である、あるいは境界がわかっているときに、 それを満たすように解析する機能です。

と書いてある通り、一部の形態素情報がわかっているときにそれを満たすように解析します。例えば、IPA辞書には「クラウド」という単語が無いので、IPA辞書を使って「クラウド」を含むテキストを分解すると「クラ」と「ウド」という2単語に分かれて出てきます。(実はN-Best解を表示していくとその中には未知語の「クラウド」として出力してくれるものも出てくるのですが。)

import MeCab


tagger = MeCab.Tagger()
print(tagger.parse("このブログはクラウド環境で動いています"))
"""
この	連体詞,*,*,*,*,*,この,コノ,コノ
ブログ	名詞,一般,*,*,*,*,*
は	助詞,係助詞,*,*,*,*,は,ハ,ワ
クラ	名詞,固有名詞,一般,*,*,*,クラ,クラ,クラ
ウド	名詞,一般,*,*,*,*,ウド,ウド,ウド
環境	名詞,一般,*,*,*,*,環境,カンキョウ,カンキョー
で	助詞,格助詞,一般,*,*,*,で,デ,デ
動い	動詞,自立,*,*,五段・カ行イ音便,連用タ接続,動く,ウゴイ,ウゴイ
て	助詞,接続助詞,*,*,*,*,て,テ,テ
い	動詞,非自立,*,*,一段,連用形,いる,イ,イ
ます	助動詞,*,*,*,特殊・マス,基本形,ます,マス,マス
EOS
"""

本来は、「クラウド」を辞書登録するべきなのですが、応急処置として、今回の文書では「クラウド」は1単語だよ、と明示できるのが制約付き解析です。

使い方は簡単で、次の二つを変更するだけです。
– MeCab起動時に -p (–partial) オプションをつける。(Pythonの場合はTagger生成時に”-p”を指定)
– 解析結果を指定したい部分は、「表層\t素性パターン」という形式で記入する。

「表層\t素性パターン」になっていない行は文断片とみなされ、普通に形態素解析されます。

素性パターン はワイルドカードとして * (アスタリスク)を使っても良いですし、名詞などとしても良いようです。「*,非自立」のようにして品詞の第二分類が非自立のものといった指定もできます。また、実は任意の文字列を設定することもでき、その場合は設定した文字列がそのまま出てきます。動詞や形容詞など品詞の一種であっても未知語処理の都合上、その文字列に当てはまらない品詞だった場合はそのまま表示されるようです。

とりあえずワイルドカードで「クラウド」だけ指定してやってみます。

tagger = MeCab.Tagger("-p")
print(tagger.parse(
    """
このブログは
クラウド\t*
環境で動いています。
    """
))
"""
この	連体詞,*,*,*,*,*,この,コノ,コノ
ブログ	名詞,一般,*,*,*,*,*
は	助詞,係助詞,*,*,*,*,は,ハ,ワ
クラウド	名詞,一般,*,*,*,*,*
環境	名詞,一般,*,*,*,*,環境,カンキョウ,カンキョー
で	助詞,格助詞,一般,*,*,*,で,デ,デ
動い	動詞,自立,*,*,五段・カ行イ音便,連用タ接続,動く,ウゴイ,ウゴイ
て	助詞,接続助詞,*,*,*,*,て,テ,テ
い	動詞,非自立,*,*,一段,連用形,いる,イ,イ
ます	助動詞,*,*,*,特殊・マス,基本形,ます,マス,マス
。	記号,句点,*,*,*,*,。,。,。
EOS
"""

「クラウド」が一単語としてみなされましたね。今回指定した「クラウド」は未知語なので読みなどは出てきませんが、制約付き解析で指定した単語が辞書にある場合はちゃんと読みも出てきます。

さて、ここからが応用です。前回の記事でN-Best解表示時のコスト計算にバグがある、という話を書いていますが実はこの制約付き解析を使うと、正しいコストが出力できます。

この先は前回の記事と見比べながら読んでください。
参考: MeCabのN-Best解のコストがどこで間違っているのか確認した

前回の記事では「すもももももももものうち」の4つ目の解析結果を取り上げました。

$ mecab -N 4 -E EOS\\t%pc\\n
すもももももももものうち
#####################################
#1~3個目の結果は省略します。以下は4番目の解。#
#####################################
すもも	名詞,一般,*,*,*,*,すもも,スモモ,スモモ
もも	名詞,一般,*,*,*,*,もも,モモ,モモ
も	助詞,係助詞,*,*,*,*,も,モ,モ
も	助詞,係助詞,*,*,*,*,も,モ,モ
もも	名詞,一般,*,*,*,*,もも,モモ,モモ
の	助詞,連体化,*,*,*,*,の,ノ,ノ
うち	名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ
EOS	21245

この、 21245は1個目のN-Best解の累積コストであって、4番目の解の累積コストでは無いのですが、そのずれの原因が、連接コストの1箇所が本当は 478 なのに、-4203 として計算されてしまっていることを確認したのでした。(詳細は前回の記事。)

ということは、本当のこの解のコストの総和は、 $21245 + (478-(-4203)) = 25926$ のはずです。

これが実は制約付き解析を使うと出力できます。

やり方は簡単で、コストの表示と制約付きを指定して起動したMeCabに、N-Best解で表示された文字列を渡すだけです。

tagger = MeCab.Tagger(
    "-p" +
    " -F %m\\t%s\\t%phl\\t%phr\\t%c\\t%pC\\t%pn\\t%pc\\t%H\\n" +
    " -E EOS\\t%s\\t%phl\\t%phr\\t%c\\t%pC\\t%pn\\t%pc\\tEOS\\n")
print(tagger.parse(
    """すもも\t名詞,一般,*,*,*,*,すもも,スモモ,スモモ
もも\t名詞,一般,*,*,*,*,もも,モモ,モモ
も\t助詞,係助詞,*,*,*,*,も,モ,モ
も\t助詞,係助詞,*,*,*,*,も,モ,モ
もも\t名詞,一般,*,*,*,*,もも,モモ,モモ
の\t助詞,連体化,*,*,*,*,の,ノ,ノ
うち\t名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ"""
))

# 以下出力結果
"""
すもも	0	1285	1285	7546	-283	7263	7263	名詞,一般,*,*,*,*,すもも,スモモ,スモモ
もも	0	1285	1285	7219	62	7281	14544	名詞,一般,*,*,*,*,もも,モモ,モモ
も	0	262	262	4669	-4158	511	15055	助詞,係助詞,*,*,*,*,も,モ,モ
も	0	262	262	4669	478	5147	20202	助詞,係助詞,*,*,*,*,も,モ,モ
もも	0	1285	1285	7219	17	7236	27438	名詞,一般,*,*,*,*,もも,モモ,モモ
の	0	368	368	4816	-4442	374	27812	助詞,連体化,*,*,*,*,の,ノ,ノ
うち	0	1313	1313	5796	-5198	598	28410	名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ
EOS	3	0	0	0	-2484	-2484	25926	EOS
"""

前回の記事に倣って、それぞれの単語の生起コストや各単語間の連接コストも全部表示したので、かえって見にくくなってて申し訳ないのですが、最終的な累積コストとして25926が出てきましたね。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です