【備忘録】 ③word2vecに変換 ~拡散されるニュースツイートを判別したい~


開発環境

Windows10
Anaconda3 (jupyter notebook)

説明と目的

ある大学生の卒論備忘録
テーマは、ニュースツイートにおいて、拡散されるものとされないものの判別器を作るというものです。
今回は、東北大学の学習済みword2vecを用いて、文書のベクトル平均で文書ベクトルを作ろうと思います。

前提条件

・東北大学のword2vecインストール済み
※Windowsでの解凍はLhaplusで行うのが良いかと思います。

参考URL

・東北大学word2vec
http://www.cl.ecei.tohoku.ac.jp/~m-suzuki/jawiki_vector/
・使い方
http://blog.hassaku-labs.com/post/pretrained-word2vec/

1. 必要なライブラリをインポート

tohoku_word2vec.ipynb
import gensim
import pandas as pd
import numpy as np
from gensim.models import KeyedVectors

2. モデルの読み込み

tohoku_word2vec.ipynb
# model読み込み
model = KeyedVectors.load_word2vec_format('C:/entity_vector/entity_vector.model.bin', binary=True)

'C:/entity_vector/entity_vector.model.bin'の部分は解凍した場所のディレクトリです。すこし時間がかかります。

3. データセットを作る

前回の前処理済みツイートを取得します。また、直近3日分のツイートと5000RT~7000RTのツイートは拡散と非拡散の判別が困難なため、除きたいため、それ以外のデータのインデックスを取得します。
ちなみに、
前回作ったデータセットはこのようになっています。

index tweet_no time text favorite_count RT_count Owakati Buzz
0 00000000 yyyy-mm-dd 時間:分:秒 XXXXXX xx xx xx x x xx 0or1
tohoku_word2vec.ipynb
# データの読み込み
acount = "@livedoornews"
df = pd.read_csv("../data/finish_preprocessing_{}.csv".format(acount))

# 直近3日間を除外
now = datetime.datetime.now()
escape = now - datetime.timedelta(days=3)
usual_news_index = [] # 非拡散ツイートのindex格納用の空リスト
buzz_news_index = [] # 拡散ツイートのindex格納用の空リスト

for index, t in zip(df.index,df["time"]):
    if df.iloc[index,6] == 1:# 拡散だったかどうか
        buzz_news_index.append(index)
    elif escape < datetime.datetime.strptime(t, '%Y-%m-%d %H:%M:%S') or 7000 > df.iloc[index,4] > 5000:#直近3日間かor5000RT~7000RTか
        pass
    else:
        usual_news_index.append(index)

print("通常ニュース数 ; {}".format(len(usual_news_index)))
print("拡散ニュース数 ; {}".format(len(buzz_news_index)))

通常ニュース数 ; 1702
拡散ニュース数 ; 144

次に、取得したindexを使って、Buzz判定と分かち書きのデータセットを作ります

tohoku_word2vec.ipynb
data_news_index = usual_news_index + buzz_news_index
sample_data = df.iloc[data_news_index].reset_index()
data = np.array(sample_data[['Buzz', 'Owakati']])
data.shape

Out[ ]: (1846, 2)

4. word2vecで数値化する

では、1つの文章ずつword2vecを用いて文章のベクトル平均を計算していいきます。

tohoku_word2vec.ipynb
result = [] # 文章ベクトルを格納するためのリスト
dict_word = [] # 学習済みword2vecに存在していた単語を格納するためのリスト
dict_escaped = [] # 学習済みword2vecに存在していなかった単語を格納するためのリスト
for i in range(data.shape[0]): #1文章ずつ取り出す
    print("{}回目 (残り{}回)".format(i+1,data.shape[0]-i-1))
    sentense_list = data[i][1].split(' ')
    vector = [] # 文章の中の単語のベクトルを格納するためのリスト
    for word in sentense_list:
        try:
            vector.append(model[word].tolist())
            dict_word.append(word)
        except:
            dict_escaped.append(word)
    result.append(np.mean(np.array(vector), axis=0).tolist())

data_vector = pd.concat([pd.DataFrame({"label" : data[:, 0].tolist()}), pd.DataFrame(np.array(result))], axis=1)
data_vector

1回目 (残り1845回)
2回目 (残り1844回)
3回目 (残り1843回)
4回目 (残り1842回)
..............
Out[ ]:

1846件の200次元のベクトル値とlabel(拡散かどうか)をpandasで格納したdata_vectorを取得します。
また、学習済みword2vecに存在していない単語はErrorになるので、try~exceptを使用しています。

5. 反映できた文書とできなかった文書

では、word2vecに存在していた文書をみてみます。

tohoku_word2vec.ipynb
dict_word = list(set(dict_word))
print(len(dict_word))
print(dict_word)

12145
['つかの間', '1969年', '対局', 'うつ病', 'シーズ', '抑制', 'リスク', '書状', '代表者', '不当', '民事訴訟', '睡眠薬', 'ザ', '溺れる', 'かぶせ', '凍結', 'B2', '遺品', '伝染', '岩根', '増え'.......]
のようになっていました。

次に、word2vecに存在していなかった単語を調べました。

tohoku_word2vec.ipynb
dict_escaped = list(set(dict_escaped))
print(len(dict_escaped))
print(dict_escaped)

2273
['後見制度', '勉強していたい!', '走塁', '6種類', 'オウムアムア', '一部店舗', '30発', '牧草地', '緑茶飲料', '数年前', '優勝争い', '太川蛭子の旅バラ', 'ゆりやん', 'アリキリ石井', '公判前整理手続き', '昨冬', 'ブラウザーゲーム', '岩手県野田村', 'みずほフィナンシャルグループ', '2軍', '大門未知子', '神戸山口組', '読解力', '夕張市長', '午後8時', '陽性反応', 'インディチャンプ'.......]

個人的に大事なのではないか?と思われる単語が入っていて残念な気がしました。まぁ、2,273件の単語しか抜かれなかったのは良いと言っていいのかな?という感じですが...

では、最後に作成したデータセットを保存します。

tohoku_word2vec.ipynb
data_vector.to_csv("../data/word2vec_result_@アカウント名.csv", index=False)

まとめと次回内容

今回は東北大学のword2vecを用いて単語のベクトル平均で文書を数値化しました。次回はこれを用いてロジスティック回帰を行いたいと思います。