毎日テキストマイニング

180日間、毎日テキストマイニングをするブログです

2018/8/25【63日目】マルコフ連鎖で文章を作ってみる

気を取り直して、今日は文章を機械的に作成していきたいと思います。

『ゼロから作るDeep Learning 2 自然言語処理編』に書いてありましたが、テキスト生成にはマルコフ連鎖というのを使うみたいです。

マルコフ連鎖とは

マルコフ連鎖とは、現在の状況のみにおいて、次の状態が起きる確率を決定することだそうです。

マルコフ連鎖(マルコフれんさ、英: Markov chain)とは、確率過程の一種であるマルコフ過程のうち、とりうる状態が離散的(有限または可算)なもの(離散状態マルコフ過程)をいう。また特に、時間が離散的なもの(時刻は添え字で表される)を指すことが多い(他に連続時間マルコフ過程というものもあり、これは時刻が連続である)。マルコフ連鎖は、未来の挙動が現在の値だけで決定され、過去の挙動と無関係である(マルコフ性)。各時刻において起こる状態変化(遷移または推移)に関して、マルコフ連鎖は遷移確率が過去の状態によらず、現在の状態のみによる系列である。特に重要な確率過程として、様々な分野に応用される。

それで、その確率を求めていけば文章を生成できるようです。Pythonのライブラリを使えば比較的簡単に実装できるそうなので、ものは試しにやっていきたいと思います。

Pythonで実装

markovify.NewlineTextがあれば良いそうです。

github.com

まずはpip install

pip install markovify

サンプルはこちらのようです。

import markovify

# Get raw text as string.
with open("/path/to/my/corpus.txt") as f:
    text = f.read()

# Build the model.
text_model = markovify.Text(text)

# Print five randomly-generated sentences
for i in range(5):
    print(text_model.make_sentence())

# Print three randomly-generated sentences of no more than 140 characters
for i in range(3):
    print(text_model.make_short_sentence(140))

手元にちょうどkaiseki.txtというのがありますので、こちらを試してみます。ファイルの中身はこんな感じです。

tweet " K 公演 終わり  た ♪♪♪ ひな な の 生誕 祭 ! ! ! ひな ちゃん お 誕生 日 おめでとう(以下、省略)

このkaisei.txtを指定して実行してみます。

実行結果。

KeyError: ('___BEGIN__', '___BEGIN__')

というエラーが出ました。どうやらサポートしていない文字を含んでいると起こるエラーのようです。気になる文字をいくつか消してみて実行してみましたら実行できました。どうやら”(ダブルクオテーション)がテキスト上にあるのが悪かったようです。

改めて実行した結果はこんな感じです。

tweet K 公演 終わり た ひな な の 生誕 祭 ! ! ひな ちゃん お 誕生 日 おめでとう ??✨ 永野 恵 ちゃん
tweet K 公演 終わり た ひな な の 生誕 祭 ! ! ひな ちゃん お 誕生 日 おめでとう ??✨ 永野 恵 ちゃん
tweet K 公演 終わり た ひな な の 生誕 祭 ! ! ! ! ! ! ひな ちゃん お 誕生 日 おめでとう ??✨ 永野 恵 ちゃん
tweet K 公演 終わり た ひな な の 生誕 祭 ! ! ひな ちゃん お 誕生 日 おめでとう ??✨ 永野 恵 ちゃん
tweet K 公演 終わり た ひな な の 生誕 祭 ! ! ひな ちゃん お 誕生 日 おめでとう ??✨ 永野 恵 ちゃん
tweet K 公演 終わり た ひな な の 生誕 祭 ! ! ! ! ! ひな ちゃん お 誕生 日 おめでとう ??✨ 永野 恵 ちゃん

全部同じですね。むしろ何も学習できていない?

Githubのページを見ていきましたら、学習するにはいくつかルールがあるようで、その1つに.で終わる文章である必要があるみたいです。

.で終わらなければ、改行を付けて、markovify.NewlineText(text)でテキストを学習させれば大丈夫だそうです。 markovify.NewlineText(text)を使ってみます。改行は!が来たら/nに置換させます。

こんな感じです。

tweet  K 公演 終わり  た ひな な の 生誕 祭 
 
 
 ひな ちゃん お 誕生 日 おめでとう ??✨ 永野 恵 ちゃん 初日 おめでとう 
 公演 って やっぱ すっごく 楽しい ね ?✨  :// t .  / JfT 4 pf 0 wLU   メイク ルーム で TV 観 て たら LIKE の プロモーション の わたし バージョン 流れ た ん だ 〜 
 びっくり 
(以下、省略)

こちらのテキストで再学習させてみます。

import markovify

# Get raw text as string.
with open("kaiseki.txt") as f:
    text = f.read()

# Build the model.
text_model = markovify.NewlineText(text)

# Print five randomly-generated sentences
for i in range(5):
    print(text_model.make_sentence())

# Print three randomly-generated sentences of no more than 140 characters
for i in range(3):
    print(text_model.make_short_sentence(140))

実行結果。

? あっという間に 折り返し ? 早 すぎる ? 唯一 の 友達 び ー ちゃん が 劇場 公演 初 出演 、 ひな な の 生誕 Tシャツ が 明日 の 10 時 〜 発売 .
おめでとう ござい ?? 嬉しい 。 。 。 。 これから も よろしく お願い し ☺ ️ ? メルセデス 選手 初 完封 初 ヒット .
?❤ ︎ 円陣 前 、 緊張 で 泣い ちゃう 恵 ちゃん が 劇場 公演 初 出演 、 ひな な 生誕 祭 .
おめでとう ござい ?? 嬉しい 。 。 これから も よろしく お願い し .
今年 も 応援 ありがとう ござい … :// t . / wnsoiq 7 nlZ # PRODUCE 48 の 実況 配信 し .
:// t . / w 8 xLetNb 88 :// t . / xUQbwdoVWu 現在 8 位 .
頑張っ て き た よ 〜 ? 大切 な 宝物 .
おめでとう ござい ?? 嬉しい 。 。 これから も よろしく お願い し ☺ ️ ? メルセデス 選手 初 完封 初 ヒット .

おぉ、色々とテキストが生成できました。 中身はとても微妙な感じですので、明日はもう少し学習させる内容をしっかりさせたいと思います。

今日の結果

今日のAKBメンバーの呟きは67件でした。 今回からはせっかくなので、共起ネットワークの図も付けたいと思います。

マジムリ学院が最後のメンバーがいたようですね。2つも画像があるとわかりやすいです。

f:id:rimt:20180828213137p:plain f:id:rimt:20180828213123p:plain

'楽しい': 15, '嬉しい': 11, 'すごい': 8, 'ない': 3, '暑い': 2, '明るい': 2, '凄い': 2, 'いい': 2, 'かわいい': 2, '有難い': 1, 'くい': 1, '上手い': 1, '面白い': 1, '美味しい': 1, '優しい': 1, '大きい': 1, '短い': 1, 'かっこよい': 1, 'ものすごい': 1, '温かい': 1, '良い': 1, 'っぽい': 1
'ステージ': 27, '今日': 21, 'エーケービーフォーティーエイト': 18, '学園': 16, '楽しい': 15, '出演': 12, '嬉しい': 11, '夏': 9, 'すごい': 8, 'こと': 8, 'たくさん': 8, '公演': 8, 'さん': 7, '楽しみ': 7, '回': 7, '汗': 7, '最後': 6, '思い出': 6, 'ちゃん': 6,
'する': 33, 'ステージ': 27, '今日': 21, 'エーケービーフォーティーエイト': 18, '学園': 16, '楽しい': 15, '出演': 12, '嬉しい': 11, 'せる': 10, 'できる': 10, '夏': 9, 'すごい': 8, 'こと': 8, 'たくさん': 8, '公演': 8, 'さん': 7, '楽しみ': 7, '回': 7, '汗': 7, '最後': 6, '思い出': 6, 'ちゃん': 6, 'かく': 6, 'くださる': 6, '頂く': 6,