#目次
1. はじめに
2. どうやって質問するか
3. 手法
4. 歌詞データの収集
5. データの前処理
6. 形態素解析
7. モデル実装による学習
8. 結果
9. 終わりに
10. 参考元
#1. はじめに
みなさんは「自由」とは、なんだと思いますか?
こういう質問を投げかけると恐らく、人の数だけの答えが返ってくるでしょう。
そこで今回は、私の好きなアーティストの椎名林檎さんにも同じ質問をしてみました。
#2. どうやって質問するか
とは言っても本人に直接聞くことは、どんなコネを使っても不可能です
ならば、椎名林檎さんが生み出す楽曲の歌詞にそのヒントがあるのではないか? ということで
Pythonを用いて類似度解析をやってみたいと思います!
#3. 手法
python
スクレイピング
Word2Vec
#4. 歌詞データの収集
Uta-netから歌詞データを取得
https://www.uta-net.com/artist/3361/
サイトのHTMLを参照し、曲名ごとに歌詞を書き込む。
base_url = "https://www.uta-net.com"
target_url = 'https://www.uta-net.com/artist/3361/'
music_num = 141
r = requests.get(target_url)
soup = BeautifulSoup(r.text, "html.parser")
url_list = []
for i in range(music_num):
href = soup.find_all("td", attrs={"class": "sp-w-100 pt-2"})[i].contents[0].get("href")
url_list.append(href)
kashi = ""
for i in range(music_num):
target_url = base_url + url_list[i]
r = requests.get(target_url)
soup = BeautifulSoup(r.text, "html.parser")
for string in soup.find_all("div", attrs={"id": "kashi_area"})[0].strings:
kashi += string
with open("kashi.txt", "w", encoding="utf-8") as f:
f.write(kashi)
#5. データ前処理
英語のみの歌詞や、英語を含む歌詞がいくつかあるため
日本語以外を削除する。
kashi = re.sub("[a-xA-Z0-9_]","",kashi)
kashi = re.sub("[!-/:-@[-`{-~]","",kashi)
kashi = re.sub(u'\n\n', '\n', kashi)
kashi = re.sub(u'\r', '', kashi)
#6. 形態素解析
「janome」ライブラリを利用し、形態素解析を行う。
形態素解析とは、簡単に言うと
文章を分解し、単語の組み合わせから文法上の意味を導き出すための手法です。
def tokenize(text):
t = Tokenizer()
tokens = t.tokenize(text)
word = []
stop_word = create_stop_word()
for token in tokens:
part_of_speech = token.part_of_speech.split(",")[0]
if part_of_speech == "名詞":
if not token.surface in stop_word:
word.append(token.surface)
if part_of_speech == "動詞":
if not token.base_form in stop_word:
word.append(token.base_form)
if part_of_speech == "形容詞":
if not token.base_form in stop_word:
word.append(token.base_form)
if part_of_speech == "形容動詞":
if not token.base_form in stop_word:
word.append(token.base_form)
return word
プログラム内部では、名詞・動詞・形容詞・形容動詞のみを抽出していきますが
「られる」のような不必要な単語も取り出してしまいます。
この無駄を省くために、次に「参照しない単語辞書」を作成します。
def create_stop_word():
target_url = 'http://svn.sourceforge.jp/svnroot/slothlib/CSharp/Version1/SlothLib/NLP/Filter/StopWord/word/Japanese.txt'
r =requests.get(target_url)
soup=BeautifulSoup(r.text, "html.parser")
stop_word=str(soup).split()
my_stop_word=['いい','いく','鳴る','外す','けたい','られる','ら','らん','yyy','♪','今夜','朝']
stop_word.extend(my_stop_word)
return stop_word
#7. モデル実装による学習
仕上げに「word2vec」を用いて、文章の意味を理解し目的の単語「自由」とは
何かを類似度計算で求める。
sentence = [tokenize(kashi)]
model = word2vec.Word2Vec(sentence, size=200, min_count=6, window=4, iter=50)
#8. 結果
これまでの内容を含むコード全体は以下のようになる。
import requests
from bs4 import BeautifulSoup
from gensim import corpora
from janome.tokenizer import Tokenizer
from gensim.models import word2vec
import matplotlib.pyplot as plt
from wordcloud import WordCloud
import re
import requests
from bs4 import BeautifulSoup
base_url = "https://www.uta-net.com"
target_url = 'https://www.uta-net.com/artist/3361/'
music_num = 141
r = requests.get(target_url)
soup = BeautifulSoup(r.text, "html.parser")
url_list = []
for i in range(music_num):
href = soup.find_all("td", attrs={"class": "sp-w-100 pt-2"})[i].contents[0].get("href")
url_list.append(href)
kashi = ""
for i in range(music_num):
target_url = base_url + url_list[i]
r = requests.get(target_url)
soup = BeautifulSoup(r.text, "html.parser")
for string in soup.find_all("div", attrs={"id": "kashi_area"})[0].strings:
kashi += string
with open("kashi.txt", "w", encoding="utf-8") as f:
f.write(kashi)
kashi = re.sub("[a-xA-Z0-9_]","",kashi)
kashi = re.sub("[!-/:-@[-`{-~]","",kashi)
kashi = re.sub(u'\n\n', '\n', kashi)
kashi = re.sub(u'\r', '', kashi)
def tokenize(text):
t = Tokenizer()
tokens = t.tokenize(text)
word = []
stop_word = create_stop_word()
for token in tokens:
part_of_speech = token.part_of_speech.split(",")[0]
if part_of_speech == "名詞":
if not token.surface in stop_word:
word.append(token.surface)
if part_of_speech == "動詞":
if not token.base_form in stop_word:
word.append(token.base_form)
if part_of_speech == "形容詞":
if not token.base_form in stop_word:
word.append(token.base_form)
if part_of_speech == "形容動詞":
if not token.base_form in stop_word:
word.append(token.base_form)
return word
def create_stop_word():
target_url = 'http://svn.sourceforge.jp/svnroot/slothlib/CSharp/Version1/SlothLib/NLP/Filter/StopWord/word/Japanese.txt'
r =requests.get(target_url)
soup=BeautifulSoup(r.text, "html.parser")
stop_word=str(soup).split()
my_stop_word=['いい','いく','鳴る','外す','けたい','られる','ら','らん','yyy','♪','今夜','朝']
stop_word.extend(my_stop_word)
return stop_word
sentence = [tokenize(kashi)]
model = word2vec.Word2Vec(sentence, size=200, min_count=6, window=4, iter=50)
print(model.wv.most_similar(positive=[u"自由"], topn=10))
それでは実行結果を見てみましょう。
[('人生', 0.9982376098632812), ('続く', 0.9981228113174438), ('東京', 0.9976206421852112), ('指', 0.9956468343734741), ('欲しい', 0.9946088790893555), ('ひとり', 0.9940176606178284), ('独り', 0.9933883547782898), ('忙しい', 0.9928935766220093), ('やる', 0.9920066595077515), ('有る', 0.991005539894104)]
このような結果が導き出されました。
これはあくまで類似度計算なので意味合いが近い単語でしかありませんが、
「人生が続く」ことが自由に繋がると解釈することもできます
私個人はかなりインドアなので「東京」は人が多く生きづらい印象を勝手ながら
受けてしまうのですが、その土地で生きた椎名林檎さんは
「自由の町」と捉えたのかもしれませんね
独りが自由なのはわかりますが、「指」というのは考え方によっては
難解な解釈が必要そうです
#9. 終わりに
今回使用したコードは似たような記事を参考にして
少し手を加えたに過ぎません。
初心者の私でも扱えるものだったので、皆さんも参考にして
色々な方に言葉の意味を問いかけてみては如何でしょうか
コーディングの勉強になるのは勿論のこと、
もしかしたらあなたの人生観が少しなりともポジティブに
なるかもしれませんよ❕❕
#10. 参考元