【Python】Janomeを使ったマルコフ連鎖に触れてみた!
IT技術
Janomeを使ってマルコフ連鎖に挑戦!
後に紹介する「マルコフ連鎖」は、統計学でよく活用されていますが、言語処理の「文書生成」でも活用できます。
具体的には、ある言葉の次に来るであろう言葉を、確率をもとにつなぎ合わせて、文章にするようなイメージですね。
今回は、この「マルコフ連鎖」と「Janome」というライブラリを使って、文書作成をしていきたいと思います!
マルコフ連鎖とは
一般的な「マルコフ連鎖」の説明では、次のように表現されています。
マルコフ連鎖とは、確率過程に一種であるマルコフ過程の中で、有限であり可算集合であるもの。
これだと、ちょっと分かりづらいですね…
簡単に噛み砕いて説明すると、マルコフ連鎖とは、次の条件を満たしたものです。
- 今の確率から未来の挙動がわかる
- ある状態が独立してバラバラである(天気の晴れ曇り雨、サイコロの1~6など)
具体的な例を出すと、今日の天気が雨なら、明日晴れになる確率は「30%」、雨になる確率は「70%」といった具合です。
Janomeのインストール
Janomeとは、日本語の「形態素分解」や「単語分解(分かち書き)」を、Python でできるようにしたライブラリです。
日本語は、英語のように単語ごとに、文書にスペースなどが入っているわけではありません。
つまり、単語分解(分かち書き)をすることが、難しい言語なのです。
それを容易にしたのが、この「Janome」。
類似のライブラリには、「MeCab」もありますね!
Janomeのインストール
それでは、インストールしていきましょう!
Janome は、pip コマンドで、簡単にインストールすることができます。
1pip install janome
難しいセットアップは要りません。
これだけで、Janome を利用することができます。
Janomeで「形態素分解」してみよう!
文章の「形態素分解」をしてみる
インストールした Janome を使って、文章の「形態素分解」をしてみましょう!
書くべきコードは、次のとおりです。
1# janomeのライブラリからTokenizerオブジェクトオブジェクトを取得します
2# Tokenizerを使うことことで形態素分解を行っていきます。
3from janome.tokenizer import Tokenizer
4
5# オブジェクト生成
6t = Tokenizer()
7
8# tokenizeメソッドを使て文書を読み込みます。
9tokens = t.tokenize("初めまして、私がこの記事の作者です。")
10
11# printで実行結果の確認
12for value in tokens:
13print(value)
では、上のコードを実行してみましょう。
結果
すると、次のような結果が表示されます。
1>>> 初め 名詞,副詞可能,*,*,*,*,初め,ハジメ,ハジメ
2>>> まして 副詞,一般,*,*,*,*,まして,マシテ,マシテ
3>>> 、 記号,読点,*,*,*,*,、,、,、
4>>> 私 名詞,代名詞,一般,*,*,*,私,ワタシ,ワタシ
5>>> が 助詞,格助詞,一般,*,*,*,が,ガ,ガ
6>>> この 連体詞,*,*,*,*,*,この,コノ,コノ
7>>> 記事 名詞,一般,*,*,*,*,記事,キジ,キジ
8>>> の 助詞,連体化,*,*,*,*,の,ノ,ノ
9>>> 作者 名詞,一般,*,*,*,*,作者,サクシャ,サクシャ
10>>> です 助動詞,*,*,*,特殊・デス,基本形,です,デス,デス
11>>> 。 記号,句点,*,*,*,*,。,。,。
このように、Janome を使うことで、簡単に文章の「形態素分解」を行うことができました!
Janomeとマルコフ連鎖を使って「文章生成」もしてみた
今回のマルコフ連鎖では、「プレフィックスを2つ」「サフィックスを1つ」として、実施していきます。
全体のイメージとしては、プレフィックスに入った単語(今回の場合は2つ)をもとに、そこから予測される次の単語を入れて、予測を繰り返していくというイメージです。
まずは、下のマルコフ連鎖を実装した関数を見ていきましょう!
コード
1# janmeのTokenizerをimportする
2from janome.tokenizer import Tokenizer
3# random関数を使うためにrandomのライブラリをimport
4import random
5# reモジュールを使用するためにreライブラリをimport
6import re
7
8# マルコフ連鎖を使った関数を作成
9def make_Sentences(text):
10 # Tokenizerを使えるように設定します。
11 t = Tokenizer()
12
13 # janomeを使って文書を単語ごとに分解します。
14 tokens = t.tokenize(text)
15 result = []
16
17 # token.surfaceで単語だけを取得します。
18 # 取得した単語をlist内に保存していきます。
19 for token in tokens:
20 result.append(token.surface)
21
22 # 上記で分解した文書から得た単語からマルコフ連鎖ができるようにデータを格納するための
23 # 辞書データを作成します。
24 dict_data = {}
25
26 # 単語を格納するためのPrefixを設定
27 Prefix1 = ""
28 Prefix2 = ""
29
30 for value in result:
31 # Prefixの中に単語が設定されているかをチェックしています。
32 if Prefix1 and Prefix2:
33 # 辞書データに単語を格納していきます。
34 dict_data[(Prefix1,Prefix2)] = []
35 dict_data[(Prefix1,Prefix2)].append(value)
36
37 # Prefix1, Prefix2にPrefix2 ,valueをセットしてスライドします。
38 # イメージ)Prefix1 ← Prefix2, Prefix2 ← value
39 Prefix1, Prefix2 = Prefix2 ,value
40
41 # 辞書データから文書を作成するために辞書データのkeyから単語取得します。
42 Prefix1, Prefix2 = random.choice(list(dict_data.keys()))
43
44 # whileを使ってループさせるので無限ループを防ぐためにカウントをセットします。
45 count = 0
46
47 # Sentencesに作成した文書を格納していきます。
48 Sentences = ""
49
50 # もとになるlistの中身の数文だけ繰り返すように設定します。
51 while count < len(result):
52 # Prefix1, Prefix2の要素が辞書データのkeyの要素にあるかを確認します。
53 if ((Prefix1, Prefix2) in dict_data) == True:
54 # 辞書データから単語を取得して文書を作成していきます。
55 word = random.choice(dict_data[(Prefix1, Prefix2)])
56 Sentences += word
57 # Prefix1, Prefix2にPrefix2 ,wordをセットしてスライドします。
58 # # イメージ)Prefix1 ← Prefix2, Prefix2 ← word
59 Prefix1, Prefix2 = Prefix2, word
60 # 繰り返しの回数をカウントしていきます。
61 # ※もし追加しておかないと無限ループします。
62 count += 1
63
64 # 最初の句点(。)までを取り除きます。
65 Sentences = re.sub("^.+?。", "", Sentences)
66 # 句点(。)までの文書を取得します。
67 search = re.search(".+。",Sentences)
68 if search:
69 Sentences = search.group()
70 print(Sentences)
今回は、このマルコフ連鎖の関数を使っていきます。
文章を読み込ませる
ではこの関数に、下記のような、適当な文書を読み込ませてみましょう。
この文書をもとに、新たな文章を生成するわけですね!
1text = [
2 """
3 この本と私が出会ったきっかけは本屋さんでこのティファニーでという言葉を見てからです。
4 それは高校生の憧れという感じで、大人になり切れていない自分がこの本を読むことで大人になることができるのかななんて思いながら選んで手に自然ととっていました。
5 そこから嬉しく思い自宅にいそいそ持って帰り、学校帰りに買ったので楽しみに夜に読もうと思い、夕ご飯を済ませて、お風呂も済ませて楽しみにこの新しいブックカバーのついたものを部屋のベットの横に
6 置いて読まれる時を待っているように本が綺麗に輝いていました。自分のこれからの人生に変わることが起こるのかと思えるくらいにわくわくしてお風呂もいつもと同じ場所なのに新鮮に感じて幸せな感じ
7 に包まれていて、身体の汚れを落として綺麗になってからこの素敵な本の世界に入っていくのかなと想像を巡らせていました。このティファニーで朝食をの簡潔な紹介ですが、これは自分の中では恋愛の物語です。
8 夢見る男女の人生を共にしていく相手を選んでいるとも言えますが、ホリー・ゴライトリーは天真爛漫で田舎からこのニューヨークに来てもう一年くらいにもなるが今だ定職にもついていなくて、その時に飲み屋
9 で知り合った男性などに援助してもらっている生活で、でも男性たちはホリーの不思議な魅力に惹きつけられる。何人もホリーに付きまとい、ドレスを破かれるということもあったり、生活は貯金も中々出来て
10 いい状態で、朝帰りでティファニーの宝石店の前で悲しい気分を楽しくして家に帰るのがホリーの生活です。
11 """
12]
13
14make_Sentences(text[0])
実行結果
実行してみた結果がこちら。
1>>> 夢見る男女の人生を共にして家に帰るのがホリーの生活です。
ちょっと不思議ではありますが、文章らしくなっていますね!
ちなみにこの関数は、ランダム関数を使用しているため、毎回同じ結果が出るわけではありません。
何度か実行して、どんな文章が生成されるのか、試すのも楽しいですね!
文書をより大きいものにすれば、より多様な文章を出力することもできますよ。
さいごに
今回は、「Janome」と「マルコフ連鎖」を使用して、言語処理に触れてみました。
文章生成の精度を上げるには、
- プレフィックス数を増やす
- より長い文書を読み込ませた状態の辞書を準備する
など、パラメータの調整をすることも重要になってきます。
色々試して、「bot」を作成してみるのも面白そうですね!
こちらの記事もオススメ!
2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...
2020.07.30Python 特集実装編※最新記事順Responder + Firestore でモダンかつサーバーレスなブログシステムを作ってみた!P...
ライトコードでは、エンジニアを積極採用中!
ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。
採用情報へ
「好きを仕事にするエンジニア集団」の(株)ライトコードです! ライトコードは、福岡、東京、大阪、名古屋の4拠点で事業展開するIT企業です。 現在は、国内を代表する大手IT企業を取引先にもち、ITシステムの受託事業が中心。 いずれも直取引で、月間PV数1億を超えるWebサービスのシステム開発・運営、インフラの構築・運用に携わっています。 システム開発依頼・お見積もり大歓迎! また、現在「WEBエンジニア」「モバイルエンジニア」「営業」「WEBデザイナー」を積極採用中です! インターンや新卒採用も行っております。 以下よりご応募をお待ちしております! https://rightcode.co.jp/recruit