別棟備忘録4

*

マルコフ連鎖による文章生成

   

これも古典的ですが。
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 : 山田君は徹夜明けに焼肉を食べる。

作文例

 - Python, 備忘録