【備忘録】④word2vecとロジスティック回帰 ~拡散されるニュースツイートを判別したい~


開発環境

Windows10
Anaconda3

説明と目的

ある文系大学生の卒論備忘録
テーマは、ニュースツイートにおいて拡散されるものとされないものを判別する判別器を作るというものです。
今回は、前回のword2vecのデータを格納したものを使ってロジスティック回帰を行いたいと思います。

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

word2vec_logistic.ipynb
import pandas as pd
import numpy as np
import random
import time
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import LeaveOneOut
from sklearn.model_selection import cross_val_score
import warnings
warnings.filterwarnings('ignore')

FutureWarningの嵐だったので、警告文は無視するようにしています。

2. データセットの取得

ちなみに、前回作ったデータはこんな感じです(一部)
..........
拡散かどうかを表すlabelと学習済みword2vecの単語のベクトル平均を文章のベクトルとして200次元で格納しています。

word2vec_logistic.ipynb
df = pd.read_csv("../data/word2vec_result_@アカウント名.csv")
# データのindex取得
usual_news_index = []
buzz_news_index = []

for index in df.index:
    if df.iloc[index,0] == 1:
        buzz_news_index.append(index)
    else:
        usual_news_index.append(index)

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

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

上のプログラミングでは、非拡散ニュースと拡散ニュースのそれぞれのindexを取得して、リストに格納しています。

3. ロジスティック回帰の実行

word2vec_logistic.ipynb
X_df = df.drop("label",axis=1)
y_df = df["label"]
Accuracy = []
All_start_time = time.time()

for times in range(100):
    print("****************************************************")
    print("回数:{}回目 (残り:{}回)".format(times+1,100-times-1))
    start_time = time.time()
    data_usual_news_index = random.sample(usual_news_index, len(buzz_news_index))
    # 分析対象データセットを作る
    data_news_index = data_usual_news_index + buzz_news_index
    X = X_df.iloc[data_news_index].reset_index(drop=True)
    X = X.values
    y = y_df.iloc[data_news_index].reset_index(drop=True)
    y = y.values
    # 予測を行うleave-one-out交差検証
    scaler = StandardScaler()
    X_scaled = scaler.fit_transform(X)
    log_reg = LogisticRegression().fit(X_scaled,y)
    loo=LeaveOneOut()
    score = cross_val_score(log_reg, X, y, cv = loo) #分類器として
    score = score.tolist()
    score = np.array(score,dtype='int64')
    Accuracy.append(sum(score)/score.shape[0])
    print(sum(score)/score.shape[0])
    finish_time = time.time()
    do_time = finish_time - start_time
    h = int(do_time)//3600
    m = int(do_time)//60 - (int(do_time)//3600)*60
    s = int(do_time) - (int(do_time)//60)*60
    print("所要時間    {}:{}:{}".format(h, m, s))

All_finish_time = time.time()
All_do_time = All_finish_time - All_start_time
All_h = int(All_do_time)//3600
All_m = int(All_do_time)//60 - (int(All_do_time)//3600)*60
All_s = int(All_do_time) - (int(All_do_time)//60)*60
print("総合所要時間    {}:{}:{}".format(All_h, All_m, All_s))

回数:1回目 (残り:99回)
0.59375
所要時間 0:0:10
.....

そんなに高くない...
とりあえず、続行...
結果的に20分21秒このプログラミングが終わるまでかかりました。個人的にかかりすぎのような...
では、結果を表示します。

word2vec_logistic.ipynb
print("平均値={:.2f}%".format(sum(Accuracy)/len(Accuracy)*100))
print("最大値={:.2f}%".format(max(Accuracy)*100))
print("最小値={:.2f}%".format(min(Accuracy)*100))

平均値=61.19%
最大値=69.10%
最小値=54.17%

まずまず...といったところでしょうか。二値判別なので若干低い気がします。

次回内容と今後の展望

次回はword2vecの数値化である程度複雑な判別器も作成し、だいたいそこが終わったら、Bertも使っていこうと考えています。
また、これらの分割結果を人間の目で見てどうなっているか分かるように可視化できればと思っています。