マルコフ連鎖による文章生成
これも古典的ですが。
Mecabにて分かち書きができたら、次は文章生成がしたくなるのが常。
マルコフ連鎖はwikipediaを読んでもあまりわかりませんが、つまり、今の状態からの遷移がそれ以前の状態にはよらない確率的遷移を続けていくようなイメージなんだと思われます。
pythonにはmarkovifyというモジュールもありますが、ちょっとブラックボックス感。
こちらのページが、原理の説明を含めて非常にわかりやすかったので、修正しながら体感的にパクります。
以下の文章からモデルを作り、作文してみます。(※以下の文章は事実ではなく、個人的な思想信条とは無関係です。)
僕はカレーが好き。伊東はカレーで有名。彼は徹夜明けに焼肉を食べたい。山田君は国語が超苦手だ。君はパスタを食べる。バイデン大統領はステーキを昨日食べた。岸田さんは総裁選を投げ出した。石破さんは総裁選に立候補する。
以下、コードなど
#モデルの生成パート import MeCab wakati = MeCab.Tagger('-Owakati ') txt_data = '僕はカレーが好き。伊東はカレーで有名。彼は徹夜明けに焼肉を食べたい。山田君は国語が超苦手だ。君はパスタを食べる。バイデン大統領はステーキを昨日食べた。岸田さんは総裁選を投げ出した。石破さんは総裁選に立候補する。' print("*******原文*******") print(txt_data) print("*******分かち書き*******") result = wakati.parse(txt_data).replace('。 ', '。\n').rstrip() print(result) print("") print("*************以下、文章処理***************") def make_1state_model(txt_data): model = {} txt_data = txt_data.split('\n') for sentence in txt_data: if not sentence: # 空行などは処理しない break eos_mark = '。!?' if sentence[-1] not in eos_mark: # 行末が。!?でなければ処理しない print('not process:', sentence) continue print("********************") print(sentence,"についての処理") words = sentence.split(' ') print(words) previous_word = 'BoS' # begin of sentence for word in words: print(word,"について処理") if previous_word in model: model[previous_word].append(word) else: model[previous_word] = [word] previous_word = word print(model) return model model = make_1state_model(result) #print(model) #文章の生成パート print("**************文章の生成****************") from random import randint def generate_sentence(model): eos_mark = '。!?' key_list = model['BoS'] key = key_list[randint(0, len(key_list)-1)] #print(key) result = key print(result)#途中経過を見るとき① while key not in eos_mark: key_list = model[key] print(key_list)#途中経過を見るとき① key = key_list[randint(0, len(key_list)-1)] result += key print(result)#途中経過を見るとき① #print(result)# 途中経過を見るとき➁ return result for i in range(1): print(i,":",generate_sentence(model))
出来上がったmodel
{
‘BoS’: [‘僕’, ‘伊東’, ‘彼’, ‘山田’, ‘君’, ‘バイデン’, ‘岸田’, ‘石破’],
‘僕’: [‘は’],
‘は’: [‘カレー’, ‘カレー’, ‘徹夜’, ‘国語’, ‘パスタ’, ‘ステーキ’, ‘総裁’, ‘総裁’],
‘カレー’: [‘が’, ‘で’],
‘が’: [‘好き’, ‘超’],
‘好き’: [‘。’],
‘伊東’: [‘は’],
‘で’: [‘有名’],
‘有名’: [‘。’],
‘彼’: [‘は’],
‘徹夜’: [‘明け’],
‘明け’: [‘に’],
‘に’: [‘焼肉’, ‘立候補’],
‘焼肉’: [‘を’],
‘を’: [‘食べ’, ‘食べる’, ‘昨日’, ‘投げ出し’],
‘食べ’: [‘たい’, ‘た’],
‘たい’: [‘。’],
‘山田’: [‘君’],
‘君’: [‘は’, ‘は’],
‘国語’: [‘が’],
‘超’: [‘苦手’],
‘苦手’: [‘だ’],
‘だ’: [‘。’],
‘パスタ’: [‘を’],
‘食べる’: [‘。’],
‘バイデン’: [‘大統領’],
‘大統領’: [‘は’],
‘ステーキ’: [‘を’],
‘昨日’: [‘食べ’],
‘た’: [‘。’, ‘。’],
‘岸田’: [‘さん’],
‘さん’: [‘は’, ‘は’],
‘総裁’: [‘選’, ‘選’],
‘選’: [‘を’, ‘に’],
‘投げ出し’: [‘た’],
‘石破’: [‘さん’],
‘立候補’: [‘する’],
‘する’: [‘。’]}
つまり、「は」のあとは2/8の確率で「カレー」、2/8の確率で「総裁選」、以下、「徹夜」、「国語」、「パスタ」、「ステーキ」がそれぞれ1/4の確率で出現する。
作文される様子
**************文章の生成****************
山田
[‘君’]
山田君
[‘は’, ‘は’]
山田君は
[‘カレー’, ‘カレー’, ‘徹夜’, ‘国語’, ‘パスタ’, ‘ステーキ’, ‘総裁’, ‘総裁’]
山田君は徹夜
[‘明け’]
山田君は徹夜明け
[‘に’]
山田君は徹夜明けに
[‘焼肉’, ‘立候補’]
山田君は徹夜明けに焼肉
[‘を’]
山田君は徹夜明けに焼肉を
[‘食べ’, ‘食べる’, ‘昨日’, ‘投げ出し’]
山田君は徹夜明けに焼肉を食べる
[‘。’]
山田君は徹夜明けに焼肉を食べる。
0 : 山田君は徹夜明けに焼肉を食べる。