データ分析
2024/02/15
稲川

BERTによる、歌詞に基づくMr.Childrenの曲の分類に挑戦!【Part①】

in-ear headphones plugged in black Sony Walkman on vinyl record

Mr.Childrenの曲を20曲取り上げ、BERTを利用して、歌詞に基づいた分類を実行してみました。

はじめに

BERT(Bidirectional Encoder Representations from Transformers)というモデルをご存知でしょうか?BERTは、Googleが開発した自然言語処理のための深層学習モデルです。これは、高度な言語理解タスクを実行するために開発され、文章の要約、文書分類、質問応答、言語翻訳など、様々なところで応用されています。


本記事では、BERTを用いて、歌詞に基づいたMr.Childrenの曲の分類を試してみようと思います。


対象とするのは、次の20曲です。


「365日」「しるし」「終わりなき旅」「Sign」「GIFT」「名もなき詩」「Tomorrow never knows」「HERO」「エソラ」「innocent world」「くるみ」「抱きしめたい」「旅立ちの唄」「君が好き」「シーソーゲーム ~勇敢な恋の歌~」「祈り ~涙の軌道」「youthful days」「掌」「Marshmallow day」


分類は次の手順で行います。



  1. 歌詞(文字列)を数値化

  2. 数値化したベクトルをクラスター分析(K平均法)


準備

はじめに、諸々のダウンロードを済ませます。


読み込むcsvファイルには、1列目に「曲名」、2列目に「歌詞」の情報が入っています。




!pip install japanize_matplotlib
!pip install fugashi
!pip install ipadic

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import torch
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.manifold import TSNE
from transformers import BertJapaneseTokenizer, BertModel
from sklearn.cluster import KMeans

df= pd.read_csv("Mr.Children.csv")
df= df.iloc[1:20]#今回は歌詞閲覧ランキング上位20個を対象とします


次に、BERTの日本語モデルをダウンロードします。



# BERTの日本語モデル、tokenizer、modelのダウンロード 
BERT_model_jp = 'cl-tohoku/bert-base-japanese-whole-word-masking'
tokenizer = BertJapaneseTokenizer.from_pretrained(BERT_model_jp)
model = BertModel.from_pretrained(BERT_model_jp)


データフレームの中身は下の画像のようになっています。


これで準備完了です。


 

歌詞を数値化

早速、歌詞を数値データに変換したいと思います。文字列を数値に変換する役割を担うのが、先ほどインストールした、BERTモデルです。



#歌詞のベクトル化
max_length = 256
sentence_vec= []

for i in range(len(df)):
lines = df.iloc[i, 1].splitlines()
text = '\n'.join(lines)
encoding = tokenizer(
text,
max_length=max_length,
padding='max_length',
truncation=True,
return_tensors='pt'
)
with torch.no_grad():
output = model(**encoding)
last_hidden_state = output.last_hidden_state
attention_mask = encoding['attention_mask']
normalized_hidden_state = (last_hidden_state * attention_mask.unsqueeze(-1)).sum(1) / attention_mask.sum(1, keepdim=True)

sentence_vec.append(normalized_hidden_state.numpy())

#リストの形式を変更
sentence_vectors = np.vstack(sentence_vectors)


最後の、sentence_vectorsの次元は、


sentence_vectors.shape

1曲の歌詞が、768次元の数値ベクトルに変換されており、それが20曲分並んだものが、sentence_vectorsに格納されています。ここまでで、歌詞(文字)の情報を数値に変換することができました。


歌詞に基づいて、曲をグループ分け

今回は、K平均法という手法を用いてクラスタリングを行います。K平均法の実行は、次の2行のコードで行うことができます。モデルを作る際に、グループの数(n_clustersの部分)を解析者が選ぶ必要がありますが、今回は4つとしました。



kmeans = KMeans(n_clusters=4, random_state=22) 
kmeans.fit(sentence_vectors)


最後に、K平均法によるクラスタリングの結果を見てみます。



from collections import defaultdict #クラスターごとに所属するデータポイントの行をまとめる辞書を作成 
cluster_dict = defaultdict(list)

#各データポイントをクラスターごとに分類
for i, label in enumerate(kmeans.labels_): cluster_dict[label].append(df.iloc[i])
sorted_clusters = sorted(cluster_dict.keys())

#各クラスターに所属するクラスターを表示
for cluster in sorted_clusters:
print(f"クラスター {cluster} に所属する曲名:")
for data_point in cluster_dict[cluster]:
print(data_point.iloc[0])
print(" ")


結果発表!

先ほどのクラスタリングの結果、次のようにグループ分けされました。



  • クラスター0: 「しるし」「終わりなき旅」「名もなき詩」「くるみ」「抱きしめたい」「旅立ちの唄」「君が好き」「シーソーゲーム ~勇敢な恋の歌~」「祈り ~涙の軌道」「掌」

  • クラスター 1 : 「365日」「Sign」「Tomorrow never knows」「innocent world」「youthful days」 「Marshmallow day」

  • クラスター 2 :「エソラ」

  • クラスター3:「HANABI」「GIFT」「HERO」


最後に

クラスター分析によって、歌詞に基づいて曲を、4つのグループに分類をすることができました。


しかしながら、ここで、重要な過失に気がつきました。「筆者は、今回扱った20曲のMr.Childrenの歌詞、全部把握できていません。」そのため、クラスター分析の結果が、非常に良いのか、ある程度良いのか、今ひとつなのか、はっきりしたことは言えません…。


BERTを用いることで、文章データを数値データに変換することができました。文章のままだと扱いにくいデータも、数値データに変換することで、色々な分析が可能になります。今回扱ったK平均法以外にもクラスタリング手法はありますし、次元削減など他の方法を試しても面白そうです。


最後まで、読んでいただきありがとうございました!


New call-to-action