去る11月13日、BAD HOP武道館ワンマン見に行ってきました。いやぁ----、めっちゃいいライブでした。
BAD HOPとは、川崎は池上出身のHip Hopクルーです。お世辞無しでいま一番勢いのあるHip Hopクルーなのではないでしょうか。
「俺たちがここ(武道館)まで最速で来れた理由ってのはなんだと思う? 才能、努力、そんなんじゃねえよ。俺たちが跨ってるのが世界のKawasakiだからだよ」
こんなMCのあとに始まったKawasaki Drift。しびれましたね。
私はそんなに昔からHip Hopを聴いているわけでは無いですが、twitterでの反応を見ると、やっぱり日本語ラップ史に残る歴史的なライブになるんだろうなあと思いました。
最近はBAD HOPとかchelmicoとかTENG GANG STARRを聴いていますが、いまだ一番好きなラッパーはZORNです。
ZORNについて
僕がはじめてZORNを知ったのがこのMVです。
いやー、すでに公開されてから4年も経ってしまいましたが、まあかっこいいですね!半端ないです。
MCが5人いますが、ダントツでZORNがヤバイですね。次点でMARIAでしょうか。
彼のバースの初めの方にこんなリリックがあります。
金に女 派手な車そんなもんは目の錯覚
誰も彼もエゴばかり 俺は俺の絵の中
娘達と手を繋いで散歩してる江戸川
目の錯覚
エゴばかり
絵の中
江戸川
でバッチリ韻を踏んでますね。目の錯覚
とエゴばかり
は最後ちょっと怪しいですが、こまかいこたぁいいんです。
娘たちと手をつないで散歩してる江戸川
なんかもいいですね。ほっこりします。これで私の一個上です。信じられません。
この曲の出番の終わりの方ではこんなことも言っています。
みんな違ってみんないい 金子みすゞみたい
どうせ空は飛べない だから俺は俺なり
ちゃんと金子みすゞをサンプリングしてますね。実にHip Hopだと思います。みんな元ネタがわかるところも得点高いですね。無駄に誇張して自分を表現することはしていませんが、それでも高みを目指しているようなギラギラ感が垣間見える、とてもいいバースだと思います。
ZORNはアルバムもいくつか出していますが、私のお気に入りはTHE DOWNTOWNです。私はマレーシアのジャングルにある工事現場で半年間働いていた事があるのですが(もう竣工済みでなかなかに利益を出しているらしい)、朝6時半に会社のバンにのって現場に向かう際に毎日聴いていたので、個人的にはドナドナ的なアルバムです。40分くらいで終わるので通勤時に聴くのもちょうどよいボリューム感です。
さて
そろそろ本題に移りたいと思います。
今回はそんなZORNの楽曲のリリックを題材にして自然言語処理の技術に触れてみます。
Hip Hopの起源をたどると、本来そのリリックに大した意味や思いは与えられていませんでしたが、現在ではリリックそのもの内容そのものが非常に重要視されています。
そこで、ZORNの楽曲のリリックDoc2Vec
を用いてZORNの楽曲のリリックをベクトルで表して見ます。
今回はとりあえずグラフを出力するところまで実施しようと思います。
Doc2Vecの実装はフリ−のライブラリであるgensimを用いました。
Doc2Vecの詳細については今回記載しません。。
やってみた
### 歌詞ファイルの読み込み
学習にはlyric masterというツールを用いて集めた2,490曲分の歌詞と、ZORNの楽曲の中から7曲を用いました。
import glob
def read_lyrics(path):
with open(path,"r") as f:
lyric = f.read()
return lyric
path = glob.glob("./lyrics/*.txt")
lyrics = [read_lyrics(p) for p in path]
titles = [p.split('/')[-1][:-4] for p in path]
path = glob.glob("./corpus/*.txt")
lyrics.extend([read_lyrics(p) for p in path])
titles.extend([p.split('/')[-1][:-4] for p in path])
titles[:7]
>>> ['my life',
'walk this way',
'東京watch',
'Enter the downtown',
'Reverse',
'Weekend',
'Fall asleep'] # zornの曲
MeCabで分かち書き
そのままでは学習に使えないので、MeCabを用いて形態素解析を施します。
import MeCab
def mecab(lyrics: list):
dict_path = "/usr/local/lib/mecab/dic/mecab-ipadic-neologd/"
m = MeCab.Tagger(f'-Ochasen -d {dict_path}')
unrequired_parts = ["記号", "BOS/EOS", "助詞", "接続詞", "副詞", "助動詞" ]
m.parse("")
wakachi = list()
for i, sentense in enumerate(lyrics):
node = m.parseToNode(sentense)
temp = list()
while node:
if node.feature.split(',')[0] not in unrequired_parts: # 不要な品詞は追加しない
temp.append(node.surface)
node = node.next
if len(temp) > 0:
wakachi.append(temp)
return wakachi
wakachi_lyrics = mecab(lyrics)
TaggedDocumentメソッドでタグ付け
gensimのTaggedDecument
を用いて、曲のタイトルと、歌詞を紐づけます。
from gensim.models.doc2vec import Doc2Vec, TaggedDocument
print(len(titles),len(lyrics))
def tagging_document(titles, lyrics):
tagged_documents = list()
for t, l in zip(titles, lyrics):
tagged_documents.append(TaggedDocument(words=l, tags = [t]))
return tagged_documents
tagged_lyrics = tagging_document(titles, wakachi_lyrics)
Doc2Vecの学習
学習を実施します。
model = Doc2Vec(vector_size=50, window=50, min_count=1, workers=4,epochs = 500)
model.build_vocab(tagged_lyrics)
model.train(tagged_lyrics,total_examples=model.corpus_count, epochs=model.epochs)
model.save('doc2vec.model')
### 歌詞ベクトルを取得
それぞれの曲のタイトルに紐付いたベクトルを取得します。
def get_lyricvectors(titles, model):
vectors = list()
for t in titles:
vectors.append(model.docvecs[t])
print(type(vectors))
return vectors
lyric_vector = get_lyricvectors(titles,model)
umap を用いて3次元に圧縮
次元圧縮にはumapを用いてみます。umapはこちらの記事で解説されています。
import umap
reducer = umap.UMAP(n_components=3)
embedding_vector = reducer.fit_transform(lyric_vector)
embedding_vector.shape
### プロットの色とラベルを指定
図示した際にわかりやすいように色とタイトルを設定します。
適当です。
color = [1 for i in range(7)]
color.extend([0.2 for i in range(2490)])
import copy
title_text = copy.copy(titles)
title_text[7:] = '' #すべてのタイトルを表示させるとplotlyがおもすぎる
plotlyで可視化
グラフの作成にはplotlyを使ってみました。
初めて使いましたが、結構簡単です。
import plotly.plotly as py
import plotly
import plotly.graph_objs as go
import numpy as np
plotly.offline.init_notebook_mode(connected=True)
x, y, z = embedding_vector[:,0], embedding_vector[:,1], embedding_vector[:,2]
trace1 = go.Scatter3d(
x=x,
y=y,
z=z,
mode='markers+text',
marker=dict(
size=5,
color= color,
opacity=0.3
),
text = title_text
)
layout = go.Layout(
margin=dict(
l=0,
r=0,
b=0,
t=0
)
)
data = [trace1]
fig = go.Figure(data=data, layout=layout)
plotly.offline.plot(fig, filename='./simple-3d-scatter.html')
おわりに
後半はやっつけ感が多少出てしましましたが、とりあえずグラフを出力するところまでは実施できました。
今回は考察もクソも何もできていないので、今後少しずつ続きをやっていこうと思います。