形態素解析

2019年7月21日

はじめに

文章の形態素解析を行う。Python のモジュール janome を用いる。

セットアップ

$ pip install janome

形態素解析

次のようにすると、文章を単語に分けてそれぞれの品詞を得る (トークン化する) ことができる。

from janome.tokenizer import Tokenizer

s = """趙の邯鄲の都に住む紀昌という男が、天下第一の弓の名人になろうと志を立てた。己の師と頼むべき人物を物色するに、当今弓矢をとっては、名手・飛衛に及ぶ者があろうとは思われぬ。百歩を隔てて柳葉を射るに百発百中するという達人だそうである。紀昌は遥々飛衛をたずねてその門に入った。"""

t = Tokenizer()

for token in t.tokenize(s):
    part = token.part_of_speech
    if "名詞,一般" in part:
        print(token)

実行結果

邯鄲	名詞,一般,*,*,*,*,邯鄲,カンタン,カンタン
都	名詞,一般,*,*,*,*,都,ト,ト
男	名詞,一般,*,*,*,*,男,オトコ,オトコ
天下	名詞,一般,*,*,*,*,天下,テンカ,テンカ
弓	名詞,一般,*,*,*,*,弓,ユミ,ユミ
名人	名詞,一般,*,*,*,*,名人,メイジン,メイジン
志	名詞,一般,*,*,*,*,志,ココロザシ,ココロザシ
師	名詞,一般,*,*,*,*,師,シ,シ
人物	名詞,一般,*,*,*,*,人物,ジンブツ,ジンブツ
当今	名詞,一般,*,*,*,*,当今,トウギン,トーギン
弓矢	名詞,一般,*,*,*,*,弓矢,ユミヤ,ユミヤ
名手	名詞,一般,*,*,*,*,名手,メイシュ,メイシュ
飛	名詞,一般,*,*,*,*,飛,ヒ,ヒ
百発百中	名詞,一般,*,*,*,*,百発百中,ヒャッパツヒャクチュウ,ヒャッパツヒャクチュー
達人	名詞,一般,*,*,*,*,達人,タツジン,タツジン
飛	名詞,一般,*,*,*,*,飛,ヒ,ヒ
門	名詞,一般,*,*,*,*,門,モン,モン

token.surface で単語を、token.reading でその読みを取れる。

分析にフィルターを適用することもできる。

from janome.analyzer import Analyzer
from janome.charfilter import *
from janome.tokenfilter import *

s = """趙の邯鄲の都に住む紀昌という男が、天下第一の弓の名人になろうと志を立てた。己の師と頼むべき人物を物色するに、当今弓矢をとっては、名手・飛衛に及ぶ者があろうとは思われぬ。百歩を隔てて柳葉を射るに百発百中するという達人だそうである。紀昌は遥々飛衛をたずねてその門に入った。"""

char_filters = [UnicodeNormalizeCharFilter()]
token_filters = [
    CompoundNounFilter(),
    POSKeepFilter(["名詞,一般", "名詞,複合"]),
]

a = Analyzer(char_filters=char_filters, token_filters=token_filters)

for token in a.analyze(s):
    print(token)

実行結果

邯鄲	名詞,一般,*,*,*,*,邯鄲,カンタン,カンタン
都	名詞,一般,*,*,*,*,都,ト,ト
紀昌	名詞,複合,*,*,*,*,紀昌,キノアキラ,キノアキラ
男	名詞,一般,*,*,*,*,男,オトコ,オトコ
天下	名詞,一般,*,*,*,*,天下,テンカ,テンカ
弓	名詞,一般,*,*,*,*,弓,ユミ,ユミ
名人	名詞,一般,*,*,*,*,名人,メイジン,メイジン
志	名詞,一般,*,*,*,*,志,ココロザシ,ココロザシ
師	名詞,一般,*,*,*,*,師,シ,シ
人物	名詞,一般,*,*,*,*,人物,ジンブツ,ジンブツ
当今弓矢	名詞,複合,*,*,*,*,当今弓矢,トウギンユミヤ,トーギンユミヤ
名手	名詞,一般,*,*,*,*,名手,メイシュ,メイシュ
飛衛	名詞,複合,*,*,*,*,飛衛,ヒマモル,ヒマモル
百歩	名詞,複合,*,*,*,*,百歩,ヒャクホ,ヒャクホ
百発百中	名詞,一般,*,*,*,*,百発百中,ヒャッパツヒャクチュウ,ヒャッパツヒャクチュー
達人	名詞,一般,*,*,*,*,達人,タツジン,タツジン
紀昌	名詞,複合,*,*,*,*,紀昌,キノアキラ,キノアキラ
飛衛	名詞,複合,*,*,*,*,飛衛,ヒマモル,ヒマモル
門	名詞,一般,*,*,*,*,門,モン,モン

char_filters は文字列に対する前処理的なフィルターである。UnicodeNormalizeCharFilter() は文字列を正規化する。記号などを取り除きたい場合は RegexReplaceCharFilter() を用いる。

char_filters = [
    UnicodeNormalizeCharFilter(),
    RegexReplaceCharFilter("[a-zA-Z0-9./*¥n ]", ""),
]

token_filters はトークン化のフィルターである。CompoundNounFilter() は複合名詞を作る (名詞-名詞と続いたらひとつの名詞にする) ものである。POSKeepFilter() は条件に一致するものだけを通すフィルターで、逆にPOSStopFilter() は条件に合致するものは通さない。

token_filters = [
    CompoundNounFilter(),
    POSKeepFilter(["名詞,一般", "名詞,複合", "名詞,サ変接続"]),
    POSStopFilter(["名詞,接尾", "名詞,非自立"]),
]

ExtractAttributeFilter("surface") を指定すると、単語だけを得ることができる。

思ったようにいかない場合は、トークン化を 2 回に分けたりなどすればよいかもしれない。