LoginSignup
8
5

More than 5 years have passed since last update.

マルコフ連鎖を用いてなろう小説のタイトルを自動生成する

Last updated at Posted at 2018-09-03

概要

小説家になろう(通称:なろう)というサイトは、自分で小説を書いて公開できるというサイトであるが、なろうで公開されている小説タイトルは一般的に長く特徴的なものが多いとされています。そこで、文書生成の手段として有名なマルコフ連鎖を用いてなろう小説のタイトルの自動生成を行いました。

プログラム

1.title_correct.py  :  なろうのAPIを使ってなろう小説のタイトルを記録する

2.marcov.py  :  1でできたテキストファイルからMeCabを用いて分かち書きを行いマルコフ連鎖のもととなるデータベースを作成しそこからタイトルを自動作成する。

タイトルを集める

タイトルを集めるプログラムは「小説家になろう」の作品タイトルは、本当に長くなってるのか? Pandasで確認しよう(https://qiita.com/dely13/items/5e949a384161c961d8ce)
を参考にして生成しました。

title_correct.py

import pandas as pd
import requests

url = "http://api.syosetu.com/novelapi/api/"
st = 1
lim = 500

data = []
while st < 2000:
    payload = {'of': 't-gp-gf-n', 'order': 'hyoka',
          'out':'json','lim':lim,'st':st}
    r = requests.get(url,params=payload)
    x = r.json()
    data.extend(x[1:])
    st = st + lim


df = pd.DataFrame(data)
#print(df['title'])


f = open('text_title.txt', "w")
list =[] 
for i in range(2000):
    try:
        f.write(df['title'][i] + ','+'\n')
    except:
        print(i)
f.close

上記記事によるとなろうAPIの取得できるデータ数はマックス2000のようなので、総合人気ランキングトップ2000を取得しています。
すべて取得すると有象無象の小説も取得してしまうためトップ2000ぐらいがちょうどいいかもしれません。
タイトルによってはUnicodeEncodeErrorが出てしまったので例外処理を行っています。

マルコフ連鎖でのタイトルの生成

マルコフ連鎖のプログラムは[Python]マルコフ連鎖で自動文章を生成する
(https://shimi-dai.com/python-markov/)
を参考にしています。

marcov.py


# -*- coding: utf-8 -*-
import random
import MeCab
import csv

# MeCab使用してテキストデータを単語に分割する
def wakati(text):
    t = MeCab.Tagger("-Owakati")
    m = t.parse(text)
    result = m.rstrip(" \n").split(" ")
    return result
def read_csv(filename):
    f = open(filename, "r")
    csv_data = csv.reader(f)
    csv_list = [row for row in csv_data]
    f.close()
    return csv_list


if __name__ == "__main__":
    filename = "text_title.txt"


    #print(title_list[1][0])
    src = open(filename, "r").read()
    wordlist = wakati(src)
    #ten = ['.']
    #print(wordlist)

    #print(wordlist)

    # マルコフ連鎖

    markov = {}
    w1 = ""
    w2 = ""

    for word in wordlist:
        if w1 and w2:
            if (w1, w2) not in markov:
                markov[(w1, w2)] = []
                #print('w1 not in markov ', w1)
                #print('w2 not in markov ', w2)
            markov[(w1, w2)].append(word)
            #print(markov)
            #print('w1 append:', w1)
            #print('w2 append:', w2)
        w1, w2 = w2, word
        #print('w1:', w1)
        #print('w2:', w2)
#print(markov)
    while(True):
        # 文章の自動作成
        count = 0
        sentence = ""
        w2 = '.'

        w1, w2  = random.choice(list(markov.keys()))
        #print(w1)
        #print(w2)

        while count < 20:
            tmp = random.choice(markov[(w1, w2)])
            #print(tmp)
            sentence += tmp
            w1, w2 = w2, tmp
            count += 1

        t = MeCab.Tagger("-Owakati")

        node = t.parseToNode(sentence)
        node = node.next

        hinshi = node.feature.split(",")[0]
        #sprint(hinshi)
    #助詞や助動詞が先頭に来ている場合再生成する
        if(hinshi!='助詞' and hinshi != '助動詞'):
            break

    print(sentence)

日本語の文章では基本的に助詞や助動詞が先頭に来ると明らかにおかしな文になってしまうので助詞や助動詞がはじめにきていた場合再生成を行っています。

生成したタイトル

とりあえずランダムに5個生成させました。
・令嬢のその後のその後の異世界に転移するのを目指します~(旧題:
・令嬢らしい,スキル『腹痛(微弱)』が『たった一つ』しかない悪役令嬢は騎士
・姫は支配者として君臨する,白魔法師は支援職では性格が悪く、十
・ふなでなでするために淑女になるために歩む道~,そして私は兎に
・精霊術士の異世界邪神転生綺譚~,魔法使いと風精霊,メニューをどうぞ_

なかなかにカオスになりましたがなんとなくそれっぽいのがあるような気もしますw
今回の五回では生成されませんでしたが英語タイトルが生成の時邪魔することが多いのでテキストファイル生成時に省いたほうがいいかもしれません。

おまけ

何回か生成していく中で特になろうっぽいやつ
・勇者様の街で静かに暮らしたい,悪役令嬢に恋をしてもらった
・だけど、もうやめたいです。勇者の復讐譚 ~サラリーマン、異世界召喚物語
・(仮題)こちら討伐クエスト斡旋窓口無職の俺が、交渉スキルに全振りしたい
・奴隷になりたくて( ̄∇ ̄*)ゞ,転生先が少女漫画の白豚令嬢だった件

8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5