ユーニックス総合研究所

  • home
  • archives
  • python-janome-replace-tail

PythonのJanomeで文章の語尾(助動詞)を置き換える【自然言語処理, 形態素解析】

PythonのJanomeで形態素解析

人間が発する言語を「自然言語」と呼び、自然言語を単語ごとに分割する手法を「形態素解析」といいます。
PythonにはJanomeという形態素解析ライブラリがあり、これを使うと文章を簡単に解析することが可能です。

今回は形態素解析を使い、文章の特定の語尾(助動詞)を指定の語尾に置き換えるという処理を書いてみます。

Janomeのインストール

pipなどを使い↓のようにしてJanomeをインストールします。

$ pip install janome  

文章をトークン列に分解する

Janomeで文章をトークン列(解析した結果の単語の列)に分解するには、まずjanome.tokenizer.Tokenizerをインポートします。
このTokenizerをインスタンス化し、メソッドのtokenizeに自然言語が書かれた文章を渡すと、解析が行われます。

from janome.tokenizer import Tokenizer  

s = '本日は晴天なり'  # 自然言語が書かれた文章  
t = Tokenizer()  # トーカナイザー  
toks = t.tokenize(s)  # 文章を形態素解析  
print(toks)  # 結果を出力  
<generator object Tokenizer.__tokenize_stream at 0x00000270F09E8A20>  

Tokenizer.tokenize()が返す結果はgeneratorになっています。
generatorlist()に渡すとリストにすることが可能です。

print(list(toks))  
[<janome.tokenizer.Token object at 0x000001C902EAA208>, <janome.tokenizer.Token object at 0x000001C902EAA278>, <janome.tokenizer.Token object at 0x000001C902EAA2E8>, <janome.tokenizer.Token object at 0x000001C902EAA358>]  

↑のリストの中を見るとjanome.tokenizer.Tokenというオブジェクトがリスト内に格納されているのがわかります。
このトークンが形態素解析の結果のトークンであり、解析した単語の情報が格納されているものです。
また、トークン列はfor文で回すことも可能です。

from janome.tokenizer import Tokenizer  

s = '本日は晴天なり'  # 自然言語が書かれた文章  
t = Tokenizer()  # トーカナイザー  
toks = t.tokenize(s)  # 文章を形態素解析  

# トークン列を出力する  
for tok in toks:  
    print(tok)  
本日    名詞,副詞可能,*,*,*,*,本日,ホンジツ,ホンジツ  
は      助詞,係助詞,*,*,*,*,は,ハ,ワ  
晴天    名詞,一般,*,*,*,*,晴天,セイテン,セイテン  
なり    助動詞,*,*,*,文語・ナリ,基本形,なり,ナリ,ナリ  

Tokenprint()で出力すると↑のように単語の情報が一覧で出力されます。

助動詞の判定

「です」「ます」などの単語は「助動詞」に分類されます。
トークン列のトークンについて、トークンが助動詞かどうか判定できれば、文章の語尾を検出できるということになります。
janome.tokenizer.Tokenは以下の属性を持っています。

part_of_speech

これはカンマ(,)区切りで記述された品詞のリストです。
トークンが名詞や動詞、助動詞かどうか確認したい場合は、この属性を調べます。

surface

これは単語の元の文章における表現の文字列で、「表層形」と呼ばれます。
この文字列を語尾の置き換えの時に使用します。

トークンのpart_of_speechsurfaceをそれぞれ出力してみましょう。

from janome.tokenizer import Tokenizer  

s = 'ありがとうございます。良いお湯でした。'  
t = Tokenizer()  

toks = t.tokenize(s)  
for tok in toks:  
    print(f'part_of_speech[{tok.part_of_speech}] surface[{tok.surface}]')  
part_of_speech[感動詞,*,*,*] surface[ありがとう]  
part_of_speech[助動詞,*,*,*] surface[ござい]  
part_of_speech[助動詞,*,*,*] surface[ます]  
part_of_speech[記号,句点,*,*] surface[。]  
part_of_speech[形容詞,自立,*,*] surface[良い]  
part_of_speech[名詞,一般,*,*] surface[お湯]  
part_of_speech[助動詞,*,*,*] surface[でし]  
part_of_speech[助動詞,*,*,*] surface[た]  
part_of_speech[記号,句点,*,*] surface[。]  

あとは以下のようにトークン列をfor文で回し、トークンのpart_of_speech属性に「助動詞」が含まれていないかチェックすれば、助動詞を持つトークンを検出できます。

from janome.tokenizer import Tokenizer  

s = 'ありがとうございます。良いお湯でした。'  
t = Tokenizer()  

toks = t.tokenize(s)  
for tok in toks:  
    # 品詞に助動詞が含まれていないかチェックする  
    if '助動詞' in tok.part_of_speech.split(','):  
        print(tok.surface)  # 表層形を出力  
ござい  
ます  
でし  
た  

助動詞を指定の文字列に置き換える

助動詞を判定できるようになったので、あとは置き換える助動詞の表層形を決めて、その助動詞を置き換える文字列を定義します。
これは↓の場合、replace_mapというdictがそれにあたります。
for文でトークン列を回し、トークンが助動詞でかつ置き換え対象であれば、replace_mapを使ってトークンを置き換えます。

from janome.tokenizer import Tokenizer  

s = '''  
先日はありがとうございました。  
本日も引き続きよろしくお願いいたします。  
報酬はO/Xに振り込みです。  
'''  

# 目的の助動詞と置き換え後の文字列を表したマップ  
replace_map = {  
    'た': 'たんたん',  
    'ます': 'マッスル',  
    'です': 'DEATH★',  
}  
t = Tokenizer()  
toks = t.tokenize(s)  

for tok in toks:  
    # トークンが助動詞でかつ、置き換え対象なら  
    match = '助動詞' in tok.part_of_speech.split(',') and tok.surface in replace_map.keys()  
    if match:  
        # トークンの表層形の代わりに置き換え後の文字列を出力  
        word = replace_map[tok.surface]  
        print(word, end='')  
    else:  
        # トークンをそのまま出力  
        print(tok.surface, end='')  

出力結果↓。

先日はありがとうございましたんたん。  
本日も引き続きよろしくお願いいたしマッスル。  
報酬はO/Xに振り込みDEATH★。  

🦝 < ・・・・・・

おわりに

形態素解析を行うと簡単に自然言語を解析することが出来ます。
形態素解析ライブラリではMeCab等も有名ですが、こちらはJanomeに比べるといくぶん処理が速いです。
速度が気になる方は利用の検討をしてみてください。

問題

Q1: Janomeのトークンの品詞を確認したいときに参照するべき属性を答えよ

  1. surface
  2. part_of_speech
  3. base_from

Q2: Janomeで自然言語を形態素解析したい時のメソッドを答えよ

  1. Tokenizer.split()
  2. Tokenizer.join()
  3. Tokenizer.tokenize()

Q3: 文章の語尾を置き換えたい場合に有効な品詞を答えよ

  1. 副詞
  2. 動詞
  3. 助動詞

正解はこちら↓

Q1: 2
Q2: 3
Q3: 3