TeraBytesMemo

プログラミング関連で自分のメモをまとめて書いたり気が向いたら書いたり

ニコ動のごちうさ1話のコメントでword2vecで遊んでみた

ふと、ごちうさ1話のコメントから、いわゆる"ごちうさ難民"の人工知能を作れないかと思い行動。

今回は、趣旨が違って、拾ったコーパスをword2vecに通したらどうなるかのお遊びだけ。

コーパス

ニコニコ動画のコメントはドワンゴより以下のようなデータが提供されています。

情報学研究データリポジトリ ニコニコデータセット

が、ごちうさ1話のコメントを取るには古すぎたので、自分でスクレイピングしました。

その際に普通にスクレイピングしても取れなさそうなので、Seleniumを使いました。

スクレイピングの方法としては

  1. ログインが必要になるので、自分のアカウントでログイン
  2. ごちうさ1話の動画へ移動
  3. コメントが読み込まれるまで待機
  4. コメントが読み込まれたらスクロールしながらコメントのDOM情報をMongoDBに保存

という手順をSeleniumで組みました。このクローラーを1日に1回のペースで回し、約35000件のコメントを保存しました。

なおコメントに加えて、コメントの投稿時間や、コメントの投稿した再生時間も保存してあります。

ソースコードは以下に用意しました。READMEとかまだできていないですが参考にしていただければと。

githubの src/gochi_usa_scrape.py が実行スクリプトとなっています。(環境変数にユーザー名のパスワードの設定必要あり)

github.com

スクレイピングに関して

今回行った成果は、以下を参考にしたうえで行いました。
robots.txtの内容も確認いたしました。
当成果に対して何か問題があればご連絡お願いします。

Webスクレイピングの注意事項一覧 - Qiita
Webスクレイピングの法律周りの話をしよう! - Qiita
niconico利用規約 - niconico

分かち書き

こういうデータを使う際には決まって文を単語に分ける分かち書きという作業が必要があります。

その際には、形態素解析mecabと、すげえmecabの辞書mecab-ipadic-neologdを用いました。

この辞書、アニメの単語とか本当に理解してすごいです。

mecabのインストール

OS X なのでbrewを使いました

brew install mecab
brew install mecab-ipadic

また、python3で処理をしたので以下のようにライブラリをインストール

pip install mecab-python3

mecab-ipadic-neologd

以下の記事を参考にしてインストール

kivantium.hateblo.jp

mecabはインストール済みなので

git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git
cd mecab-ipadic-neologd
./bin/install-mecab-ipadic-neologd

python上でmecab-ipadic-neologdを使う場合は

mt = MeCab.Tagger('-Ochasen -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd')

と、タガーを定義する際に引数に辞書を指定する必要があります。

また、今回のコーパスは複数行にわたるAAが顕著に見られました(しかも各行が分けられて撮ってきている)

よって、形態素解析及び分かち書きの際は、文中の"記号"が6割以上超えた場合にコーパスから排除するという処理を行いました。

コードしてはこんな感じ。sent_parser関数が文の分かち書きで、parser関数が複数の文をまとめて分かち書きできる。

#!/usr/bin/env python
# coding: utf-8

import MeCab


def surface_iter(node):
    #「文頭」を無視
    node = node.next

    while node.next:
        yield (node.surface, node.feature)

        node = node.next

def sent_parser(sentence):

    dic = '/usr/local/lib/mecab/dic/mecab-ipadic-neologd'

    config = '-Ochasen'
    config += " -d {}".format(dic)
    mt = MeCab.Tagger(config)
    mt.parse('')

    node = mt.parseToNode(sentence)
    parsed = surface_iter(node)

    try:
        parsed = list(parsed)
        surfaces, features = zip(*parsed)
        new_surfaces = [sur for sur, fea in parsed]

        n_kigou = len([x for x in features if '記号' in x])
        score = n_kigou / len(features)

        return new_surfaces if score < 0.6 else []
    except ValueError: # zipに失敗したものは排除。
        return []


def parser(docs):
    parsed = map(sent_parser, docs)
    parsed = [x for x in parsed if x]

    return parsed

word2vec

gensimのword2vecを使って類似度計算を行いました。

word2vecによって、単語をベクトル表現することができ、コサイン類似度で単語の類似度を調べることができます。

"word2vec"についてわからない人は、ググると出てくるので是非ググってください。有名なモデルです。

類似度計算の際は、上記のコードの関数で分かち書きした単語列の頭に投稿した再生時間を示す記号を投入。

(例えば、再生時間01:00に投稿されたものはTM_01という記号を入れる)

具体的に、コードにするとこんな感じ(x['time'][:2]がコメントの投稿した再生時間(分単位)、x['parsed']は分かち書きしたコメント)

[['TM_' + x['time'][:2]] + x['parsed'] for x in result]

こういう細工をすることで、各再生時間で使われる単語を見ることができてニヤニヤできますw

ちなみに、各コメントを3つにコピーしてかさ増ししました。

word2vecにかけて、類似度計算をしてみた結果。

川の類似度。表示結果は川と類似する単語です。川に対して詳しい。

f:id:TeraBytesMemory:20160704174817p:plain

EUの類似度。類似する単語がめっちゃタイムリー。

f:id:TeraBytesMemory:20160704175148p:plain

濃度の類似度。空気と関係していたり薄くなったり不穏。

f:id:TeraBytesMemory:20160704180838p:plain

TM_16のデータをかさ増ししていないモデルの結果で。この時間は弾幕が濃い。

f:id:TeraBytesMemory:20160704181413p:plain

同じくかさ増しせずにTM_22。線路へほっぴんジャンプ♪

f:id:TeraBytesMemory:20160704181936p:plain

TM_○○の類似度はかさ増ししない方が面白い結果が出ました。