Np-Urのデータ分析教室

オーブンソースデータなどWeb上から入手できるデータを用いて、RとPython両方使って分析した結果を書いていきます

【Rでword2vec】AKB48と乃木坂46の歌詞を分析して「人生とは何か?」質問してみた

前回、巷で話題の「マジ卍」とはどんな意味なのか、word2vecで分析してみました。
Pythonにて、

  • Twitterデータ取得
  • MeCabによる単語分かち書き
  • word2vecで分析

ということを行ったのですが、面白い結果になったと思います。
www.randpy.tokyo

なお、word2vecって何?という方は以下をご覧ください。
www.randpy.tokyo



さて、前回はPythonでしたが今回はR実践編です。

皆さん、人生とは一体何なのか、考えたことはありますか?(急にどうした)
私も20代後半に入り、人生について考えてみたのですが……さっぱり分かりません!
ということで、word2vec先生に質問してみましょう!

今回扱うデータですが、元気をくれる曲をたくさん歌ってくれているAKB48と乃木坂46の歌詞を扱います。

  • 歌詞データをスクレイピング
  • MeCabによる単語分かち書き
  • word2vecで単語の類似度計算

という流れで行っていきます!

なお、Rでのスクレイピングについては以下の書籍、

Rによるスクレイピング入門

Rによるスクレイピング入門

word2vecを含むテキストマイニングについては以下が参考になるかと思います。

Rによるやさしいテキストマイニング 機械学習編

Rによるやさしいテキストマイニング 機械学習編

扱うライブラリ群

スクレイピングや文字列処理、単語分かち書き等で必要なライブラリを紹介します。

library(rvest)
library(tsne)
library(magrittr)
library(stringr)
library(wordVectors)
library(dplyr)
library(RMeCab)

まだ使ったことがないライブラリがある場合は、事前に

install.packages("rvest", dependencies = T)

このようにインストールしておきましょう。

なお、wordVectorsはcranからのインストールができないため、githubから落としてくる必要があります。

devtools::install_github("bmschmidt/wordVectors")

と入力してインストールしてください。

歌詞データの取得

今回は、Uta-Netさんからデータを取得してきました。

例えば、乃木坂46の曲一覧ページはこちらになります。
このページから、まずは各曲へのURLを取得します。

basic_url = "https://www.uta-net.com"
nogizaka_url = "https://www.uta-net.com/artist/12550/"
nogizaka_url_page = read_html(nogizaka_url)

url_list = nogizaka_url_page %>% 
  html_nodes(xpath = "//div[@id='artist']//table/tbody//td[@class='side td1']/a") %>%
  html_attr("href")
song_url_list = url_list[url_list %>% grep("/song/",.)]

まず、「read_html」で対象URLを取得し、その後「html_nodes」でxpath指定して必要な部分のみ抽出します。

これにて「song_url_list」という変数に、曲のURLリストが格納されました。
次に、song_url_listに入っている各曲ページに飛び、歌詞部分を取得しましょう。

lyrics = ""

for (i in 1:(song_url_list %>% length())){
  song_url = song_url_list[i]
  tmp_url = paste(basic_url, song_url_list[i], sep = "")
  
  tmp_lyrics = read_html(tmp_url) %>% 
    html_nodes(xpath = "//div[@id='kashi_area']") %>%
    html_text()
  
  lyrics = paste(lyrics, tmp_lyrics, sep = " ")
  Sys.sleep(2)
}

write.table(lyrics,"lyrics_nogizaka.txt",col.names = F,row.names = F)

やることは先ほどと同様ですね。各曲のURLを「read_html」で取得し、その後html_nodesで歌詞部分を抽出します。
そして、各曲をpaste(~)で繋げていきます。

注意点として、何も考えずデータを取得してしまうと対象サイトのサーバー負荷が上がってしまうので、

Sys.sleep(2)

として、次の曲を読み込む前に2秒ほど間隔を空けるようにしましょう。
最後に、取得した歌詞情報を「write.table(~)」で保存しておけば完了です!

AKB48の歌詞情報も同じやり方で取得し、保存しておきましょう。

MeCabで単語分かち書き

次に、MeCabで単語を分かち書きにしていきます。

rmecab_text_nogizaka = RMeCabText("lyrics_nogizaka.txt")

rmecab_text_nogizaka_list = ""
for (i in 1:(rmecab_text_nogizaka %>% length)){
  tmp_rmecab_text_nogizaka = rmecab_text_nogizaka[[i]]
  if ((tmp_rmecab_text_nogizaka[2] %in% c("名詞", "動詞","形容詞")) &&
    (tmp_rmecab_text_nogizaka[3] != "非自立")){
      rmecab_text_nogizaka_list = paste(rmecab_text_nogizaka_list, as.character(tmp_rmecab_text_nogizaka[1]), sep = " ")
  }
}
write(rmecab_text_nogizaka_list, file = "rmecab_text_nogizaka_list.bin", append = TRUE)

RMeCabText にて、テキストファイルを読み込むと同時に分かち書きにしてくれます。
これは各単語をリスト形式で持っているので、各単語ごとに必要な品詞のみ選ぶといったことや、非自立語は選ばない、といったことを指定します。

その後、word2vecを使うために単語同士を半角スペースで格納して、最後にbinファイルで保存してあげればOKです。
この辺り、例えば副詞を加えたり、動詞は除いたりしながら調節してみてください。

【番外編】Word Cloudで可視化

ここで、本筋から外れますが、せっかくなのでWord Cloudで可視化してみましょう。

Word Cloudとは単語の頻出具合によって、文字の大きさや色を変えて可視化する手法です。
RでのWord Cloud の使い方としては、以下を参考にしてみてください。
www.randpy.tokyo

乃木坂46の歌詞でよく使われている単語を可視化

まず、乃木坂46の歌詞を可視化してみましょう。

docDF_lyrics_nogizaka = docDF("lyrics_nogizaka.txt", type = 1)
docDF_lyrics_nogizaka_2 = docDF_lyrics_nogizaka %>% filter(POS1 %in% c("名詞"), POS2 != "非自立", TERM != ")", TERM != "(")
wordcloud(docDF_lyrics_nogizaka_2$TERM,docDF_lyrics_nogizaka_2$lyrics_nogizaka.txt, min.freq= 5, scale=c(6,1), family ="JP1"
, colors = brewer.pal(8,"Dark2"))

f:id:Np-Ur:20180210152900p:plain

AKB48の歌詞でよく使われている単語を可視化

次に、AKB48の歌詞を可視化してみましょう。

docDF_lyrics_akb = docDF("lyrics_akb.txt", type = 1)
docDF_lyrics_akb_2 = docDF_lyrics_akb %>% filter(POS1 %in% c("名詞"), POS2 != "非自立", TERM != ")", TERM != "(")
wordcloud(docDF_lyrics_akb_2$TERM,docDF_lyrics_akb_2$lyrics_akb.txt, min.freq= 13, scale=c(6,1), family ="JP1"
          , colors = brewer.pal(8,"Dark2"))

f:id:Np-Ur:20180210153029p:plain

差があることを期待したのですが、大体同じですね…笑。
どちらのグループの歌詞も、同じような単語が使われているようです。

こういう風に可視化してみるだけでも、面白いですし何より簡単なので、是非やってみてください!

word2vecで学習

さて、本題に戻りましょう。

ここまでで、データをスクレイピングし、必要な単語を抽出するところまでできました。
いよいよword2vecを実践しましょう。

といってもライブラリさえインストールできていれば簡単です。

model_nogizaka = train_word2vec("rmecab_text_nogizaka_list.bin", vectors = 30, window = 4, threads = 1)

vectors は、単語ベクトルの次元です。数万単語をword2vecに学習させる場合は、100~300ぐらいを指定することが多いようですが、今回単語数がそこまで多くないのでこここも少なめにしています。
なお、AKB48の方は曲数が多くその分単語数も多いので、乃木坂46よりも単語ベクトルを大きく設定してみました。

windowはどこまでを周辺語とするかです。一般的な文章だともう少し広くすると思うのですが、歌詞なので狭く設定してみました。
vectorsとwindowsは結果を見つつ、いい感じに値を変化させてみてください。

threadsは並列処理する場合に、お使いのPCのコア数を元に2以上の値を設定すればOKです。



お疲れ様でした!これにて全作業は終了です!

word2vecの結果を確認

さて、最初の目的である「人生とは何なのか」、AKB48と乃木坂46の歌詞を学習したword2vec先生に質問してみましょう!
ある単語との意味が近い単語を拾ってくる場合は、closet_toを用います。

AKB48で学習したword2vec

まずはAKB48の歌詞を学習したword2vec先生から。

> model_akb %>% closest_to(model_akb [["人生"]])
       word similarity to model_akb[["人生"]]
1      人生                           1.0000000
2      仕事                           0.8862265
30.8803747
4      休む                           0.8796321
50.8646808
6    ネオン                           0.8528280
7    ノック                           0.8505839
8  あわせる                           0.8505046
9      彼氏                           0.8480094
100.8443461

一番上の『人生』は(もちろん類似していて当たり前なので)除くと、
「人生とは仕事」という結果に……笑

ただその下には『休む』という単語も。

無理やり繋げて、「人生とは適度に休んで適度に仕事をするものだ」と解釈しました。
うん、まさに私の人生とはこんな感じ。

乃木坂46で学習したword2vec

続きまして、乃木坂46の歌詞を学習したword2vec先生にも訊いてみましょう。

model_nogizaka %>% closest_to(model_nogizaka [["人生"]])
       word similarity to model_nogizaka [["人生"]]
1      人生                     1.0000000
2      しよ                     0.9594008
3  抱きしめ                     0.9406284
4      希望                     0.9393446
5      欲望                     0.9379345
6      違う                     0.9343063
70.9335523
8      大人                     0.9332920
9    生きる                     0.9326301
10     僕ら                     0.9322630

「人生とは希望」
「人生とは欲望」
「人生とは生きる」
などなど、何だか抽象的な意味が出てきました。

「人生とは希望」が個人的には気に入っています。

まとめ

今回はRでword2vecを実践してみよう、ということで、AKB48と乃木坂46の歌詞を使って分析してみました。
通常word2vecにかけるデータよりも少ないと思いますが、何だかそれっぽい結果が出てきて、「word2vecさんスゲー」と思っています。

まとめると、
人生とは希望であり、適度に休み適度に仕事するという欲望を持って生きるべし
ということになりました。(強引ですが…笑)

皆さんもそんな素敵な人生を送ってください!!