Python で「あの人が言いそうなこと」を生成する
「あの人の言葉をもっと聞いていたい」
そう思うこと、ありませんか。
雑学、格言、極端だけど妙に引力のある言葉、などなど、Twitter 等で「見る専用」としてフォローしているアカウントなど、誰しも一つや二つあるのではないでしょうか。
そして、そんな発言をもっと聞きたいと思った時、更新がなく困ったことはないでしょうか。
そんな時は、その人が言いそうなことを自動で生成してしまいましょう。
例えばこちらの記事では本田圭佑が言いそうなことを自動生成しています。
ここではもっと身近に、ラインのトーク履歴から発言を取得し、自分の身の周りの誰かがいいそうなことを自動生成してみます。これで気になるあの子やあいつからのラインが来なくても、発言を生成することで「あ、いいそういいそう〜」と楽しむことができます。
自動生成の流れは以下の通りです。
- ラインからトーク履歴を取得
- 前処理
- 学習&生成
なお、文章生成の学習データには、このブログを運営してるもう一人との個人ラインを使いました。
ラインからトーク履歴を取得
スマホでラインを開き、取得したいトーク履歴のチャットルームに入って「右上の三本線(iPhone)→その他→トーク履歴を送信」で適当な場所にトーク履歴を保存しておきます。
これを Python で読み込みます。
import pandas as pd
path_talk = './talk.txt'
talk = pd.read_table(path_conversation, names=['date', 'name', 'text']).drop_na()
.txt の中身は綺麗に何かで区切られているわけではないため、明示的に names
で列数、列名を指定してます。また、日付が変わる部分などところどころに NaN があるため削除しています。
前処理
生成したい発言をする人を決め、データをフィルタします。
people = talk['name'].unique()
text = talk.query('name == @people[0]')['text'].tolist()
形態素解析を行い、単語をわかち書きしていきます。
import MeCab
parser = MeCab.Tagger('-Owakati')
text_parse = [parser.parse(text_i) for text_i in text]
発言の一つ一つがわかち書きされたものを1つの要素としたリストが出来上がりました。これをベースに発言生成を行います。
学習&生成
markovify
を使ってモデル学習と発言生成を行います。
# 学習
model = markovify.NewlineText(text_parse, state_size=3, well_formed=False)
state_size
は、何回続いて出現する形態素を一塊とするかを表します。例えば、「昨日の夕飯はラーメンだった」をわかち書きすると「昨日 の 夕飯 は ラーメン だっ た」になりますが、state_size=3
だと「昨日 の 夕飯」「の 夕飯 は」…と言ったように、3つの形態素を一塊とし、「その次にどんな単語が来そうか」を学習します。state_size
を小さくしすぎると組み合わせが多く柔軟な構成になり過ぎて、しばしばよくわからない文を生成します。一方で、state_size
を大きくしすぎると、そもそもそんな組み合わせ滅多にないということになり、生成自体できなかったり生成が失敗しやすくなります。
# 生成
sentence = model.make_short_sentence(max_chars=30, min_chars=10, tries = 300).replace(' ', '')
print(sentence)
「笑」がつくところが逆に生々しく、人を心配させることができそうな短文が生成されました。ちなみにこの人が病んでるところを見たことはありません。
make_short_sentence()
は元の文章と被りすぎないような文章を成功したら生成した文章を返しますが、そうでない場合は None
を返します。この際に何回生成してみるかの試行回数が tries
です。
10回生成してみた結果です。
for i in range(0,10):
print(model.make_short_sentence(max_chars=30, min_chars=10, tries = 300).replace(' ', ''))
ちょっと違和感がありますが、まあまあよく生成できてると思います。いい歳して「かんぢ」といった語尾を使っていることはさておき、内容も割と本人っぽいです。
State_size を変えてみて、並べて表示してみます。
State_size=1は最も柔軟な生成であるため、よくわかんなくなってます。反対に5だと違和感は全くありません(?)が、文章にバリエーションがなくなり、内容も過去の発言をただ引っ張ってきてるだけという結果になっています。
皆さんのお手元ではどうでしょうか、これで無口なあの人を饒舌にしてしまいましょう。