なろう小説と自然言語処理

はじめに

こんにちは。当サークルメンバーの石屋です。

近所を歩くとツツジやら春紫苑やらが植え込みから元気よく咲き乱れていて、春だなぁと感じるこの頃ですが、皆さんはいかがお過ごしでしょうか。

さて、なろう小説について今更語る必要はないと思いますが、なろうはWeb小説の巨大プラットフォームとして名を馳せており、そこから商業化する作品も多いです。

一方で、広義の人工知能の界隈では自然言語処理が流行っています。分かち書き、翻訳などをはじめ、最近では感情を分析する、自動で小説を書く、対話するなどのモデルも考案されています。

自然言語処理の対象としてシェイクスピアなどの古典がよく利用されるんですが、僕が知る限り、なろう小説はまだ大規模に解析されている例が少ないです。

ここでは

・解析の流れの共有
・語彙の解析、感情分析など
・人気度について回帰した予測
・需要があればサービスとして公開(?)

などを目的として、多少実用性を狙いつつ主に筆者の自然言語処理の勉強として、なろう小説を解析するコラムを書いていこうと思います。
更新頻度は不定期です。需要がありそうならやる気が出ます。

分かち書き

第一回目として、有名な作品の分かち書きをし、形態素に分解して、全シリーズを通して使ってる単語の頻度とかをみてみます。

環境としては、Google Colaboratoryで書いてます。BeautifulSoapを使うと自動でスクレイピングできます。取得部はこんな感じ。get_all_body_textsに小説のidを入れると、全章取得できます。特にコードに興味がない場合は読み飛ばしてください。

def ID_to_url_of_each_scene(id):
    url = f"https://ncode.syosetu.com/{id}/"
    bs = BeautifulSoup(urlopen(url),"lxml")
    hrefs = {}
    for a_element in bs.find_all(href=re.compile(f"\/{id}/\d+/")):
        hrefs[a_element.get('href')] = a_element.get_text()
    return hrefs


def get_body_text(url):
    bs1 = BeautifulSoup(urlopen(url),"lxml")
    p_elements = bs1.find_all("p",attrs={"id":re.compile("L\d+")})
    body_text = "".join([p_element.get_text() for p_element in p_elements]).replace("\u3000", "")
    return body_text

def get_all_body_texts(id):
    hrefs = ID_to_url_of_each_scene(tensura)
    all_text = ""
    for chapter_index, href in enumerate(hrefs.keys()):
        url = "https://ncode.syosetu.com"+href
        body_text = get_body_text(url)
        print(chapter_index, body_text[:20])
    all_text += body_text
 return all_text

形態素解析はJanomeを使うと簡単でした。今回は名詞、形容詞、動詞を取り出してきます。

tokenizer = Tokenizer()
token_filters = [POSKeepFilter(['名詞','形容詞','動詞'])]
ana = Analyzer(char_filters=[], tokenizer=tokenizer, token_filters=token_filters)
tokens = ana.analyze(all_text)
words = []
p = re.compile('[\u3041-\u309F]+')
for token in tokens:
    if p.fullmatch(token.surface) is None:
        words.append(token.surface)

今回は『転生したらスライムだった件』の全文を取得して分かち書きしてみました。

出現頻度が上位の単語を、(単語、頻度)の形式で見てみます。


[('事', 8968),
('俺', 5813),
('達', 4766),
('者', 3750),
('"', 3239),
('人', 2885),
('何', 2318),
('無い', 2312),
('能力', 2161),
('出来', 2153),
('魔王', 2092),
('魔', 1903),
('自分', 1894),
('ヴェルドラ', 1682),
('一', 1616),
('リムル', 1521),
('力', 1520),
('魔物', 1476),
('今', 1455),
('様', 1438),
('言っ', 1324),
('魔法', 1311),
('考え', 1303),
('出来る', 1260),
('話', 1217),
('王', 1208),
('目', 1202),
('時', 1185),
('可能', 1156),
('攻撃', 1083),
('相手', 1078),

事、俺やリムルなどの固有名詞の出現が多いのは当然として、ここでは、攻撃、魔王、魔物、魔法、王などのファンタジー用語がしっかり出現頻度が高いことが見て取れます。もう少し下の方のランクも見てみます。

('ソウエイ', 486),
('究極', 486),
('情報', 482),
('カルマン', 482),
('言わ', 477),
('性', 477),
('行動', 465),
('魂', 464),
('命令', 463),
('我', 458),
('戦い', 454),
('ヴェルダ', 452),
('子供', 450),
('様子', 448),
('完全', 447),
('魔力', 447),
('皆', 441),

上位500件までをまとめてみました。ざっとみた感じ、ファンタジー用語+戦争関連の用語が多かったように思います。自明といえば自明ですね。

名詞がリストに出現することが多かったので、形容詞と動詞にも絞ってみます。

[('無い', 2312),
('出来', 2118),
('言っ', 1324),
('出来る', 1260),
('思っ', 1062),
('考え', 1048),
('言う', 1002),
('来', 964),
('良い', 926),
('見', 886),
('思う', 763),
('行っ', 669),
('出', 607),
('持つ', 565),
('知れ', 559),
('受け', 549),
('言わ', 477),
('無かっ', 412),
('聞い', 410),
('言え', 408),
('無く', 407),
('行う', 399),
('得', 396),
('感じ', 386),
('向け', 377),
('言い', 364),
('持っ', 361),
('考える', 358),
('来る', 349),
('出し', 340),
('信じ', 328),
('強', 325),
('思わ', 323),
('居', 308),
('見る', 306),
('知ら', 300),
('気付い', 296),
('強い', 282),
('見せ', 282),
('見え', 275),
('始め', 269),
('良かっ', 262),
('知っ', 260),
('与え', 257),
('思い', 256),
('言える', 251),
('過ぎ', 250),
('悪い', 249),
('高い', 242),
('良く', 239),
('任せ', 235),
('入っ', 230),
('出す', 227),
('欲しい', 224),
('出る', 222),
('止め', 220),
('認め', 211),
('行く', 209),
('居る', 202),
('慌て', 201),
('思え', 198),
('死ん', 194),
('浮かべ', 190),
('許さ', 190),
('上手く', 185),
('生き', 181),
('判ら', 178),
('貰っ', 176),
('守る', 174),
('大きく', 172),
('入れ', 172),
('違う', 170),
('残っ', 169),
('戻っ', 168),
('放っ', 168),
('聞き', 167),
('貰う', 166),
('起き', 165),
('付け', 165),
('聞く', 162),
('感じる', 162),
('戦っ', 161),
('戦う', 161),
('行い', 159),
('教え', 159),
('動く', 158),
('呼ば', 158),
('行わ', 155),
('下さい', 155),
('待っ', 154),
('諦め', 154),
('立つ', 154),
('殺す', 153),
('死ぬ', 153),
('続け', 153),
('やって来', 153),
('殺し', 153),
('入る', 153),
('消え', 151),
('聞こえ', 150),
('終わり', 150),

基本的な言う、考え、などの動詞が多いのは当然として、下の方からようやく殺す、死ぬ、終わり、などのこの作品ならでは(かもしれない)動詞が含まれ始めてるかもしれないです。

改善点と次にやりたいこと

なろう全体として自明な名詞、動詞とかが抽出されまくっている気がします。
もっと作品数を増やして(上位100とか?)、あまり人気でない作品との語彙やその分布の差分を取ってみると面白いのかもしれないです。
暇があれば人気度を回帰したモデルとか作ってみたいです。

おまけ:ジップの法則

こんな経験則が実はあります。

ジップの法則(ジップのほうそく、Zipf's law)あるいはジフの法則とは、出現頻度が k 番目に大きい要素が、1位のものの頻度と比較して 1/kに比例するという経験則である。(wikipedia)

転スラの場合、単語全体の分布はこんな感じでした。

スクリーンショット 2021-04-25 15.56.51

頻度とrankのlogを取ってみます。(PS:当初この図は間違ってたので直しました)

スクリーンショット 2021-04-25 18.39.21

rankが1000くらいまでの単語はこの法則に従ってそうですが、それ以降になると出現頻度が下がっています。つまり、あまり出現しない単語については、法則から予想されるよりも出現頻度が少ないです。何か意味があるのかもしれないです。

うぉおおおおお。

以上。



この記事が参加している募集

#文学フリマ

11,850件

この記事が気に入ったらサポートをしてみませんか?