唯物是真 @Scaled_Wurm

プログラミング(主にPython2.7)とか機械学習とか

小説家になろうのランキングをトピックモデルで解析(gensim)

小説家になろうというWeb小説投稿サイトがあります。
いわゆるライトノベル的な作品が多いのですが、近年書籍化される作品が多く出ていて注目を集めています。

小説を読もう! || 小説ランキング[累計]の上位100件を解析して、どんな作品が多いのか調べてみました。

解析手法

トピックモデルというものを用います。
これは文書が何のトピックを含むかを推定してくれるモデルで、他にもトピックの代表的な単語などもわかります。

Pythonでトピックモデルを使えるライブラリの一つであるgensim: Topic modelling for humansを使います。

gensim

gensimはLDAやLSIなど複数のトピックモデルを実装しています。
今回はLDA(Latent Dirichlet Allocation)というモデルを使って解析をしました。
gensimの日本語解説は以下の記事が詳しいです。

詳細

今回は作品の本文ではなく、作者がつけたタグを利用します。
それぞれの作品を文書、作品に付いているタグを文書中の単語とみなしてトピックモデルを適用します。

前処理として以下の関数を用いて、出現頻度が3未満または50より多いタグは除去しています。
gensim.corpora.dictionary.Dictionary.filter_extremes

dictionary.filter_extremes(3)

gensim: Tutorialsをみると簡単にLDAが使えることがわかります。
以下はソースコードからの抜粋です。
tagsはリストのリストになっていて、作品ごとのタグのリストが含まれています。
これをDictionaryを使ってコーパスの形式に変換した後LdaModelに渡せば結果が得られます。

    dictionary = gensim.corpora.Dictionary(tags)
    dictionary.filter_extremes(3)
    corpus = [dictionary.doc2bow(text) for text in tags]
    lda = gensim.models.ldamodel.LdaModel(corpus=corpus, num_topics=10, id2word=dictionary)
    for x in lda.show_topics(-1, 5):
        print x

出現するタグ

f:id:sucrose:20130426015613p:plain:w600
以下が出現頻度の上位10件となっています。
「残酷な描写あり」の「異世界」「ファンタジー」が多いことがわかります。

タグ名 頻度
残酷な描写あり 73
R15 69
異世界 55
ファンタジー 50
魔法 26
チート 21
転生 14
冒険 12
主人公最強 9
ハーレム 9

トピックモデルの結果

トピック数を10とし、得られたトピックの代表的な単語を5個ずつ出力しました。

出力をみると異世界ファンタジーものや最近流行りの「VRMMO」*1もの、他にも「主人公最強」*2や「内政」*3などがとれていそうなことがわかります。

0.103*チート + 0.103*転生 + 0.103*トリップ + 0.054*ファンタジー + 0.054*魔法
0.204*精霊 + 0.019*ファンタジー + 0.019*VRMMO + 0.019*魔法 + 0.019*チート
0.109*貴族 + 0.109*内政 + 0.074*ファンタジー + 0.074*ハーレム + 0.074*国家/民族
0.200*魔法 + 0.112*ファンタジー + 0.112*チート + 0.090*学園 + 0.068*主人公最強
0.115*ファンタジー + 0.070*成長 + 0.070*奴隷 + 0.070*成り上がり + 0.070*コメディー
0.265*ファンタジー + 0.119*チート + 0.061*剣と魔法 + 0.061*勇者 + 0.032*冒険
0.169*魔法 + 0.089*ファンタジー + 0.089*チート + 0.089*VRMMO + 0.089*最強
0.176*ファンタジー + 0.083*魔法 + 0.073*転生 + 0.052*チート + 0.052*主人公最強
0.209*VRMMO + 0.086*魔法 + 0.086*ネットゲーム + 0.086*VRMMORPG + 0.045*ファンタジー
0.257*ファンタジー + 0.172*冒険 + 0.088*魔法 + 0.088*モンスター + 0.059*ハッピーエンド

まとめ

小説家になろう作品のタグからある程度トピックを抽出できた。

載せていないが、タグだけでなくあらすじでもやろうかと思ったものの、そちらはあまりうまくいかず。
この記事を書き上げた後にググったら以下の気合の入ったスライドを発見。
全小説(20万件以上)のあらすじを取得して形態素解析後にトピックモデルで解析しているとのこと。

おまけとして18禁版のサイトを解析した結果をこのページの下の方に載せてあります。

ソースコード

gensimの他にもHTMLの解析用にBeautifulSoupを利用しています。
実行するたびに結果が変わります。
毎回ランキングページのHTMLをダウンロードしているので、あまり短期間に連続で実行しないように注意。

# -*- coding: utf-8 -*-
import urllib2
from bs4 import BeautifulSoup
import gensim

def getNarouRankingHTML():
    return urllib2.urlopen('http://yomou.syosetu.com/rank/list/type/total_total/')

def getNarouRankingTags(soup):
    return [[item.string for item in div.find_all('a') if item.string != None] for div in soup.find_all(class_='novel_h')]

if __name__ == "__main__":
    html = getNarouRankingHTML()
    soup = BeautifulSoup(html)
    tags = getNarouRankingTags(soup)
    
    dictionary = gensim.corpora.Dictionary(tags)
    dictionary.filter_extremes(3)
    corpus = [dictionary.doc2bow(text) for text in tags]
    lda = gensim.models.ldamodel.LdaModel(corpus=corpus, num_topics=10, id2word=dictionary)
    for x in lda.show_topics(-1, 5):
        print x

おまけ - 18禁なので注意

小説家になろうの男性向け18禁版であるノクターンノベルズムーンライトノベルズに対して同様の解析をしてみました。
ソースコード中のランキングのURLの部分だけを書き換えれば動作します。

ノクターンノベルズ

男性向けのサイトです。
ノクターンノベルズ || 小説ランキング[四半期]を解析。
f:id:sucrose:20130427175749p:plain:w600

0.129*ファンタジー + 0.065*奴隷 + 0.065*異世界 + 0.065*チート + 0.049*近親相姦
0.075*中出し + 0.074*女子高生 + 0.074*美少女 + 0.057*調教 + 0.057*アナル
0.102*ファンタジー + 0.062*女子高生 + 0.042*近親相姦 + 0.042*調教 + 0.042*美少女
0.067*奴隷 + 0.067*鬼畜 + 0.067*監禁 + 0.067*近親相姦 + 0.046*ファンタジー
0.078*巨乳 + 0.041*奴隷 + 0.041*近親相姦 + 0.041*ガールズラブ + 0.041*チート
0.100*R15 + 0.067*ファンタジー + 0.067*奴隷 + 0.067*調教 + 0.056*メイド
0.100*異世界 + 0.100*美少女 + 0.100*R15 + 0.068*奴隷 + 0.068*チート
0.140*ファンタジー + 0.114*近親相姦 + 0.058*妊娠 + 0.058*異種姦 + 0.032*ガールズラブ
0.077*中出し + 0.077*学校 + 0.053*ファンタジー + 0.052*女子高生 + 0.052*凌辱
0.172*ファンタジー + 0.077*処女 + 0.058*強姦/レイプ + 0.058*女子高生 + 0.058*異世界

ムーンライトノベルズ

女性向けのサイトです。
BEST100と書いてありますが、なぜか300個のランキングです。

ムーンライトノベルズ || 四半期ランキング[女性向け]

f:id:sucrose:20130427181000p:plain:w600

0.052*ファンタジー + 0.052*残酷な描写あり + 0.052*じれじれ + 0.052*社会人 + 0.035*年の差
0.090*残酷な描写あり + 0.065*ファンタジー + 0.052*恋愛 + 0.039*R15 + 0.039*年の差
0.132*残酷な描写あり + 0.073*ファンタジー + 0.061*異世界 + 0.037*R15 + 0.037*恋愛
0.102*残酷な描写あり + 0.097*R15 + 0.072*恋愛 + 0.047*らぶえっち + 0.047*ハッピーエンド
0.113*恋愛 + 0.081*残酷な描写あり + 0.072*ハッピーエンド + 0.069*ファンタジー + 0.052*溺愛
0.077*R15 + 0.060*恋愛 + 0.060*溺愛 + 0.052*残酷な描写あり + 0.035*異世界
0.153*恋愛 + 0.065*ファンタジー + 0.047*ハッピーエンド + 0.036*現代 + 0.036*らぶえっち
0.084*R15 + 0.072*溺愛 + 0.053*恋愛 + 0.053*残酷な描写あり + 0.053*執着
0.079*溺愛 + 0.055*ファンタジー + 0.055*R15 + 0.043*ハッピーエンド + 0.037*恋愛
0.067*らぶえっち + 0.051*残酷な描写あり + 0.051*ファンタジー + 0.051*複数 + 0.034*恋愛
ムーンライトノベルズ || 四半期ランキング[BL]

f:id:sucrose:20130427181416p:plain:w600

0.087*学園 + 0.061*R15 + 0.053*恋愛 + 0.044*残酷な描写あり + 0.035*コメディ
0.079*残酷な描写あり + 0.079*ファンタジー + 0.059*無理矢理 + 0.059*高校生 + 0.040*溺愛
0.151*残酷な描写あり + 0.093*ファンタジー + 0.089*R15 + 0.051*R18 + 0.035*異世界トリップ
0.060*R15 + 0.060*ハッピーエンド + 0.041*ファンタジー + 0.041*残酷な描写あり + 0.041*社会人
0.069*残酷な描写あり + 0.057*R15 + 0.057*恋愛 + 0.035*ファンタジー + 0.035*BL
0.106*ファンタジー + 0.082*残酷な描写あり + 0.068*R15 + 0.039*異世界トリップ + 0.039*魔法
0.102*R15 + 0.087*残酷な描写あり + 0.063*ファンタジー + 0.055*異世界 + 0.055*ハッピーエンド
0.087*ファンタジー + 0.071*残酷な描写あり + 0.048*R15 + 0.040*恋愛 + 0.040*異世界
0.083*ファンタジー + 0.064*高校生 + 0.052*ハッピーエンド + 0.045*R15 + 0.032*残酷な描写あり
0.097*残酷な描写あり + 0.060*ファンタジー + 0.045*執着 + 0.045*無理矢理 + 0.038*騎士

*1:ソードアート・オンラインなどの仮想現実系

*2:チートな能力を持った主人公が俺ツエーする

*3:現代知識などを使って領地経営などをする、いわゆる知識チート