👨‍💻

pyknpで形態素解析と構文解析をする方法【python】

2024/06/09に公開

はじめに

こんにちは。

aiチャットボットを作る時は自然言語処理(NLP)をする必要があります。
その自然言語処理には、形態素解析や構文解析、意味解析などの工程があります。

この記事では形態素解析も構文解析も出来るpyknpの使い方を解説します。

※インストール方法はネットに載っている情報でお願いします。

pyknpとは

pyknpとは、京都大学が作ったknpとjumanをpythonで使うためのライブラリです。
因みに、knpは構文解析をするためのもので、jumanは形態素解析をするためのものです。

しかし、knpはjumanに依存しているので、knpだけで形態素解析も構文解析も出来ます(多分、コマンドラインでは構文解析しか出来ないと思います)

以下ホームページなど。

https://nlp.ist.i.kyoto-u.ac.jp/?PyKNP
https://pyknp.readthedocs.io/en/latest/

形態素解析をする方法

まず、形態素解析をする方法から説明します。
pyknpで形態素解析をする方法は二つあり、一つ目はjumanでする方法、二つ目はknpでする方法があります。

最初に、jumanで形態素解析をする方法を説明します。

まず、pyknpからJumanというクラスをインポートします。
そのクラスで新しい変数を定義します。
その変数のanalysis関数に形態素解析したい文章を入れます。
それを以下のようにfor文を使い形態素を取得します。

#import
from pyknp import Juman

#変数
#import
from pyknp import Juman

#変数
juman = Juman()

#形態素解析
result = juman.analysis("私はりんごを食べた。")
#for文で形態素を取得
for mrph in result.mrph_list():
    print(f"""見出し:{mrph.midasi}, 読み:{mrph.yomi}, 原型:{mrph.genkei}, 品詞: {mrph.hinsi}, 品詞細分類:{mrph.bunrui}, 活用型: {mrph.katuyou1}, 活用形: {mrph.katuyou2}, 意味情報:{mrph.imis}, 代表表記: {mrph.repname}\n""")

結果:

見出し:私, 読み:わたし, 原型:私, 品詞: 名詞, 品詞細分類:普通名詞, 活用型: *, 活用形: *, 意味
情報:代表表記:私/わたし 漢字読み:訓 カテゴリ:人, 代表表記: 私/わたし

見出し:は, 読み:は, 原型:は, 品詞: 助詞, 品詞細分類:副助詞, 活用型: *, 活用形: *, 意味情報:NIL, 代表表記: 

見出し:りんご, 読み:りんご, 原型:りんご, 品詞: 名詞, 品詞細分類:普通名詞, 活用型: *, 活用形: *, 意味情報:代表表記:林檎/りんご カテゴリ:植物;人工物-食べ物 ドメイン:料理・食事, 代表表記: 
林檎/りんご

見出し:を, 読み:を, 原型:を, 品詞: 助詞, 品詞細分類:格助詞, 活用型: *, 活用形: *, 意味情報:NIL, 代表表記: 

見出し:食べた, 読み:たべた, 原型:食べる, 品詞: 動詞, 品詞細分類:*, 活用型: 母音動詞, 活用形: タ形, 意味情報:代表表記:食べる/たべる ドメイン:料理・食事, 代表表記: 食べる/たべる

見出し:。, 読み:。, 原型:。, 品詞: 特殊, 品詞細分類:句点, 活用型: *, 活用形: *, 意味情報:NIL, 代表表記:

これでjumanを使って形態素解析が出来ます。

次に、knpを使って形態素解析をする方法を説明します。

knpで形態素解析をするには、jumanの時のコードに少し変更を加えれば出来ます。
することは、JumanだったところをKNPに、Juman.analysisknp.parseに変更するだけです。

#import
from pyknp import KNP

#変数
knp = KNP()

#形態素解析
result = knp.parse("私はりんごを食べた。")

#for文で形態素を取得
for mrph in result.mrph_list():
    print(f"""見出し:{mrph.midasi}, 読み:{mrph.yomi}, 原型:{mrph.genkei}, 品詞: {mrph.hinsi}, 品詞細分類:{mrph.bunrui}, 活用型: {mrph.katuyou1}, 活用形: {mrph.katuyou2}, 意味情報:{mrph.imis}, 代表表記: {mrph.repname}\n""")

結果:

見出し:私, 読み:わたし, 原型:私, 品詞: 名詞, 品詞細分類:普通名詞, 活用型: *, 活用形: *, 意味
情報:代表表記:私/わたし 漢字読み:訓 カテゴリ:人, 代表表記: 私/わたし

見出し:は, 読み:は, 原型:は, 品詞: 助詞, 品詞細分類:副助詞, 活用型: *, 活用形: *, 意味情報:NIL, 代表表記: 

見出し:りんご, 読み:りんご, 原型:りんご, 品詞: 名詞, 品詞細分類:普通名詞, 活用型: *, 活用形: *, 意味情報:代表表記:林檎/りんご カテゴリ:植物;人工物-食べ物 ドメイン:料理・食事, 代表表記: 
林檎/りんご

見出し:を, 読み:を, 原型:を, 品詞: 助詞, 品詞細分類:格助詞, 活用型: *, 活用形: *, 意味情報:NIL, 代表表記: 

見出し:食べた, 読み:たべた, 原型:食べる, 品詞: 動詞, 品詞細分類:*, 活用型: 母音動詞, 活用形: タ形, 意味情報:代表表記:食べる/たべる ドメイン:料理・食事, 代表表記: 食べる/たべる

見出し:。, 読み:。, 原型:。, 品詞: 特殊, 品詞細分類:句点, 活用型: *, 活用形: *, 意味情報:NIL, 代表表記:

構文解析をする方法

次に、構文解析をする方法を説明します。

構文解析は形態素解析と違い、knpでしか出来ないので、
knpでの構文解析の仕方を解説します。

まずさっきと同様、pyknpからKNPというクラスをインポートします。
次に、そのクラスで新しい変数を定義します。
その変数のparse関数に構文解析したい文章を入れます。
それを以下のようにfor文を使い分節を取得します。

#import
from pyknp import KNP

#変数
knp = KNP()

#構文解析
result = knp.parse("私はりんごを食べた。")

#for文で分節を取得
for bnst in result.bnst_list():
    print(f"""id: {bnst.bnst_id}, 見出し: {"".join(mrph.midasi for mrph in bnst.mrph_list())}, 係り受けタイプ: {bnst.dpndtype}, 親分節id: {bnst.parent_id}, 素性: {bnst.fstring}\n""")

結果:

id: 0, 見出し: 私は, 係り受けタイプ: D, 親分節id: 2, 素性: <文頭><一人称><SM-主体><SM-人><ハ><助詞><体言><一文字漢字><係:未格><提題><区切:3-5><主題表現><格要素><連用要素><
正規化代表表記:私/わたし><主辞代表表記:私/わたし>

id: 1, 見出し: りんごを, 係り受けタイプ: D, 親分節id: 2, 素性: <ヲ><助詞><体言><係:ヲ
格><区切:0-0><格要素><連用要素><正規化代表表記:林檎/りんご><主辞代表表記:林檎/りんご>

id: 2, 見出し: 食べた。, 係り受けタイプ: D, 親分節id: -1, 素性: <文末><時制-過去><句点><用言:動><レベル:C><区切:5-5><ID:(文末)><係:文末><提題受:30><主節><格要素><連用要素><正規化代表表記:食べる/たべる><主辞代表表記:食べる/たべる>

おわりに

これらが、pyknpの使い方です。
pyknpを使うと、形態素解析と構文解析ごとにライブラリを使わなくて良いのでとても楽です。

さようなら。

Discussion