自然言語処理についても手を伸ばしてみようと思い、AI academyさんのサイトで勉強を始めました。
無料でみられるコンテンツでちょろっと勉強したので、アウトプットとして、『羅生門』の形態素解析をやってみたいと思います。
形態素解析とは?
形態素解析とは、私たちが普段生活の中で一般的に使っている言葉、つまり「自然言語」を形態素にまで分割する技術のことです。
形態素とは、言葉が意味を持つまとまりの単語の最小単位のことです。
例えば、「私は台所で料理します」という文章を形態素解析すると「私(代名詞)/は(副助詞)/台所(名詞)/で(助詞)/料理(名詞)/し(動詞)/ます(助動詞)」というように言葉を分割していきます。
形態素解析により、文章テキストを品詞単位でばらばらにすることが可能です。
形態素=言葉が意味をもつまとまりの単語の最小単位、とありますが、厳密には形態素=単語とはならないようなので注意です。
その点に関しては、以下のサイトで丁寧に解説されています。
https://qiita.com/icoxfog417/items/e83383263badec7a4805
羅生門のテキストデータを入手する
まずは羅生門のテキストデータを入手します。
羅生門は著作権が切れており、青空文庫のウェブサイトから無料でダウンロードすることが可能です。
まずは以下のサイトにアクセスします。
https://www.aozora.gr.jp/cards/000879/card127.html#download
“127_ruby_150.zip”ファイルをダウンロードしておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
from janome.tokenizer import Tokenizer import zipfile #データを取得 zip = "127_ruby_150.zip" #ダウンロードしたzip zip_file = zipfile.ZipFile(zip,"r") f = zip_file.open("rashomon.txt","r") data = f.read() print(data) ''' b'\x97\x85\x90\xb6\x96\xe5\r\n\x8aH\x90\xec\x97\xb4\x94V\x89\xee\r\n\r\n-------------------------------------------------------\r\n\x81y\x83e\x83L\x83X\x83g\x92\x86\x82\xc9\x8c\xbb\x82\xea\x82\xe9\x8bL\x8d\x86\x82\xc9\x82\xc2\x82\xa2\x82\xc4\x81z\r\n\r\n\x81s\x81t\x81F\x83\x8b\x83r\r\n\x81i\x97\xe1\x81j\x89\xba\x90l\x81s\x82\xb0\x82\xc9\x82\xf1\x81t\r\n\r\n\x81b\x81F\x83\x8b\x83r\x82\xcc\x95t\x82\xad\x95\xb6\x8e\x9a\x97\xf1\x82\xcc\x8en\x82\xdc\x82\xe8\x82\xf0\x93\xc1\x92\xe8\x82\xb7\x82\xe9\x8bL\x8d\x86\r\n\x81i\x97\xe1\x81j\x8f\x8a\x81X\x81b\x92O\x93h\x81s\x82\xc9\x82\xca\x82\xe8\x81t\x82\xcc\x94\x8d\x81s\x82\xcd\x81t\x82\xb0\x82\xbd\r\n\r\n\x81m\x81\x94\x81n\x81F\x93\xfc\x97\xcd\x8e\xd2\x92\x8d\x81@\x8e\xe5\x82\xc9\x8aO\x8e\x9a\x82\xcc\x90\xe0\x96\xbe\x82\xe2\x81A\x96T\x93_\x82\xcc\x88\xca\x92u\x82\xcc\x8ew\x92\xe8\r\n\x81@\x81@\x81@\x81i\x90\x94\x8e\x9a\x82\xcd\x81AJIS X 0213\x82\xcc\x96\xca\x8b\xe6\x93_\x94\xd4\x8d\x86\x81A\x82\xdc\x82\xbd\x82\xcd\x92\xea\x96{\x82\xcc\x83y\x81[\x83W\x82\xc6\x8ds\x90\x94\x81j\r\n\x81i\x97\xe1\x81j\x81\xa6\x81m\x81\x94\x81u\x82\xc4\x82\xd6\x82\xf1\x81{\x89N\x81v\x81A\x91\xe64\x90\x85\x8f\x802-12-93\x81n\r\n-------------------------------------------------------\r\n\r\n\x81@\x82\xa0\x82\xe9\x93\xfa\x82\xcc\x95\xe9\x95\xfb\x82\xcc\x8e\x96\x82\xc5\x82\xa0 ''' |
zipfileを用いて、解答し、中にある”rashomon.txt”ファイルを読み込みます。
そのままだと文字化けしてしまうので、デコードしましょう。
1 2 3 4 5 6 |
text = data.decode("shift_jis") #文字化け対策 text ''' '羅生門\r\n芥川龍之介\r\n\r\n-------------------------------------------------------\r\n【テキスト中に現れる記号について】\r\n\r\n《》:ルビ\r\n(例)下人《げにん》\r\n\r\n|:ルビの付く文字列の始まりを特定する記号\r\n(例)所々|丹塗《にぬり》の剥《は》げた\r\n\r\n[#]:入力者注\u3000主に外字の説明や、傍点の位置の指定\r\n\u3000\u3000\u3000(数字は、JIS X 0213の面区点番号、または底本のページと行数)\r\n(例)※[#「てへん+丑」、第4水準2-12-93]\r\n-------------------------------------------------------\r\n\r\n\u3000ある日の暮方の事である。一人の下人《げにん》が、羅生門《らしょうもん》の下で雨やみを待っていた。\r\n\u3000広い門の下には、この男のほかに誰もいない。ただ、所々|丹塗《にぬり》の剥《は》げた、大きな円柱《まるばしら》に、蟋蟀《きりぎりす》が一匹とまっている。羅生門が、朱雀大路《すざくおおじ》にある以上は、この男のほかにも、雨やみをする市女笠《いちめがさ》や揉烏帽子《もみえぼし》が、もう二三人はありそうなものである。それが、この男のほかには誰もいない。\r\n\u3000何故かと云うと、この二三年、京都には、地震とか辻風《つじかぜ》とか火事とか饑饉とか云う災《わざわい》がつづいて起った。そこで洛中《らくちゅう》のさびれ方は一通りではない。旧記によると、仏像や仏具を打砕いて、その丹《に》がついたり、金銀の箔《はく》がついたりした木を、路ばたにつみ重ねて、薪《たきぎ》の料《しろ》に売っていたと云う事である。洛中がその始末であるから、羅生門の修理な(以下略) ''' |
Janomeを用いてテキストを形態素解析する
はじめに最終的なコードを書いておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
t = Tokenizer() words = {} lines = text.split("\r\n") for line in lines: l = t.tokenize(line) for w in l: word = w.surface part = w.part_of_speech if part.find("名詞")<0: continue if not word in words: words[word] = 0 words[word] += 1 keys = sorted(words.items(), key=lambda x:x[1], reverse=True) for word, cnt in keys[:10]: print(word,cnt) |
では細かく見ていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#形態素分析 t = Tokenizer() #形態素を入れる辞書の作成 words = {} #改行コードで区切る lines = text.split("\r\n") print(lines) ''' ['羅生門', '芥川龍之介', '', '-------------------------------------------------------', '【テキスト中に現れる記号について】', '', '《》:ルビ', '(例)下人《げにん》', '', '|:ルビの付く文字列の始まりを特定する記号', '(例)所々|丹塗《にぬり》の剥《は》げた', '', '[#]:入力者注\u3000主に外字の説明や、傍点の位置の指定', '\u3000\u3000\u3000(数字は、JIS X 0213の面区点番号、または底本のページと行数)', '(例)※[#「てへん+丑」、第4水準2-12-93]', '-------------------------------------------------------', '', '\u3000ある日の暮方の事である。一人の下人《げにん》が、羅生門《らしょうもん》の下で雨やみを待っていた。', '\u3000広い門の下には、この男のほかに誰もいない。ただ、所々|丹塗《にぬり》の剥《は》げた、大きな円柱《まるばしら》に、蟋蟀《きりぎりす》が一匹とまっている。羅生門が、朱雀大路《すざくおおじ》にある以上は、この男のほかにも、雨やみをする市女笠《いちめがさ》や揉烏帽子《もみえぼし》が、もう二三人はありそうなものである。それが、この男のほかには誰もいない。', (以下略)] ''' |
まずはじめにテキストデータを改行コードで区切ります。
linesには、上記のように改行コード間の文章のまとまりが入ります。
t.tokenize(line)
で、テキストをトークンに変換します。
例えば、lines[0]には”羅生門”というテキストが入っていますが、これをトークンに変換し表示させると以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
print(lines[0]) ''' '羅生門' ''' l = t.tokenize(lines[0]) print(l) ''' [<janome.tokenizer.Token object at 0x000002034E61D518>] ''' for w in l: print(w) print(w.surface) print(w.part_of_speech) ''' 羅生門 名詞,固有名詞,一般,*,*,*,羅生門,ラショウモン,ラショーモン 羅生門 名詞,固有名詞,一般,* ''' |
形態素解析結果に対して、surfaceを用いるとその中の単語部分を、part_of_speechを用いると品詞と品詞細分類の箇所だけ抽出することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
for line in lines: l = t.tokenize(line) for w in l: word = w.surface part = w.part_of_speech if part.find("名詞")<0: continue if not word in words: words[word] = 0 words[word] += 1 |
w.surfaceで各段落ごとに、形態素の単語部分を取り出して、それを辞書(words)に追加します。
複数回同じ単語が出るたびに、1加算していきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
keys = sorted(words.items(), key=lambda x:x[1], reverse=True) for word, cnt in keys[:10]: print(word,cnt) ''' 下人 45 の 32 事 28 老婆 28 よう 27 上 21 門 16 それ 14 死骸 14 雨 12 ''' |
このままでは、辞書の中身が単語が出てきた順番になっているので、sortedを用いて、単語の出現回数が多い順に並び替えています。
並び替えた辞書に対して、最初の10個の中身を表示しました。
おわり
結果を見ると、「下人」という単語が45回で一番出現回数が多いようです!
まだまだ自然言語処理の入り口の入り口くらいのところですが、これからもっと勉強を進めて行こうと思います。
最後までよんでいただきありがとうございました。