Spotify APIで再生回数トップ50の曲データを取得するでは、Spotify APIで再生回数トツプ50の曲一覧を取得した。Spotify APIでは、曲名やアーティスト名などの情報のほかに、曲の特徴を取得できる。曲の特徴とは、ダンスに適した曲か、エネルギッシュさなどといったもので、これらの情報を利用して曲の分類と可視化をしてみる。
環境
WSL2(Ubuntu20.04)とJupyter。
$ lsb_release -dr Description: Ubuntu 20.04.4 LTS Release: 20.04 $ python3 -V Python 3.8.10 $ jupyter --version jupyter core : 4.7.1 jupyter-notebook : 6.2.0 qtconsole : 5.0.2 ipython : 7.20.0 ipykernel : 5.4.3 jupyter client : 6.1.12 jupyter lab : 3.0.9 nbconvert : 6.0.7 ipywidgets : 7.6.3 nbformat : 5.1.2 traitlets : 5.0.5
Spotify APIで再生回数トップ50の曲データを取得するの手順でspotipyをインストールしておく。
さらに、曲を特徴でクラスタリングして可視化するためのPythonライブラリをインストールする。
$ pip3 install scikit-learn pandas matplotlib seaborn
spotipyで曲の特徴を取得
APIで取得できる特徴の説明はGet Track's Audio Featuresにある。今回はacousticness(アコースティック度)、danceability(ダンスに適した曲か)、energy(エネルギッシュさ)、instrumentalness(ボーカルがない度合い)、liveness(ライブ感)、loudness(曲全体のボリューム)、speechiness(話し言葉の度合い)、valence(曲のポジティブ度)を使用する。
import pandas as pd import spotipy from spotipy.oauth2 import SpotifyClientCredentials # language='ja'としないとアーティスト名が英語表記になる spotify = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials(), language='ja') def get_tracks(playlist_id): results = spotify.playlist_items( playlist_id, fields=None, limit=50, offset=0, market='JP', additional_types=('track', 'episode'), ) items = results['items'] tracks = [] for item in items: data = {} track = item['track'] data['track_id'] = track['id'] data['track_name'] = track['name'] data['artists'] = [ar['name'] for ar in track['artists']] tracks.append(data) return tracks def get_track_features(track_ids): results = spotify.audio_features(track_ids) # idと分類に使用する特徴 features = ['id', 'danceability', 'energy', 'loudness', 'speechiness', 'acousticness', 'instrumentalness', 'liveness', 'valence', 'tempo'] track_features = [] for re in results: track_features.append( {key: value for key, value in re.items() if key in features} ) return track_features # プレイリストの曲一覧取得 # トップ50 日本 # URLの最後の22文字がプレイリストID playlist_id = '37i9dQZEVXbKXQ4mDTEBXq' tracks = get_tracks(playlist_id) track_info = {tr['track_id']: f'{tr["track_name"]} - {"|".join(tr["artists"])}' for tr in tracks} # 曲の特徴を取得 track_ids = [tr['track_id'] for tr in tracks] track_features = get_track_features(track_ids) df_feature = pd.DataFrame([tf for tf in track_features]) df_feature.set_index('id', inplace=True) df_feature.info()
Index: 50 entries, 4IfrM44LofE9bSs6TDZS49 to 3oQaOjaIYPsnJbGNzXcIIDData columns (total 9 columns):# Column Non-Null Count Dtype--- ------ -------------- -----0 danceability 50 non-null float641 energy 50 non-null float642 loudness 50 non-null float643 speechiness 50 non-null float644 acousticness 50 non-null float645 instrumentalness 50 non-null float646 liveness 50 non-null float647 valence 50 non-null float648 tempo 50 non-null float64
クラスタリングによる分類と可視化
まずはK平均法でクラスタリングする。クラスター数は今回はとりあえず5とする。そして、その結果をもとにクラスターごとの曲を表示する。
%matplotlib inline import matplotlib.pyplot as plt import seaborn as sns import pandas as pd import spotipy from spotipy.oauth2 import SpotifyClientCredentials from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler # language='ja'としないとアーティスト名が英語表記になる spotify = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials(), language='ja') def get_tracks(playlist_id): results = spotify.playlist_items( playlist_id, fields=None, limit=50, offset=0, market='JP', additional_types=('track', 'episode'), ) items = results['items'] tracks = [] for item in items: data = {} track = item['track'] data['track_id'] = track['id'] data['track_name'] = track['name'] data['artists'] = [ar['name'] for ar in track['artists']] tracks.append(data) return tracks def get_track_features(track_ids): results = spotify.audio_features(track_ids) # idと分類に使用する特徴 features = ['id', 'danceability', 'energy', 'loudness', 'speechiness', 'acousticness', 'instrumentalness', 'liveness', 'valence', 'tempo'] track_features = [] for re in results: track_features.append( {key: value for key, value in re.items() if key in features} ) return track_features def kcluster(df): X = StandardScaler().fit_transform(df) # とりあえずクラスター数5 n_clusters = 5 clusterer = KMeans(init='k-means++', n_clusters=n_clusters, random_state=0) kmeans = clusterer.fit(X) return kmeans.labels_ # プレイリストの曲一覧取得 # トップ50 日本 # URLの最後の22文字がプレイリストID playlist_id = '37i9dQZEVXbKXQ4mDTEBXq' tracks = get_tracks(playlist_id) track_info = {tr['track_id']: f'{tr["track_name"]} - {"|".join(tr["artists"])}' for tr in tracks} # 曲の特徴を取得 track_ids = [tr['track_id'] for tr in tracks] track_features = get_track_features(track_ids) df_feature = pd.DataFrame([tf for tf in track_features]) df_feature.set_index('id', inplace=True) df_feature.info() # K平均法でクラスタリング df_feature['cluster'] = kcluster(df_feature.values) # クラスターごとの曲名を表示 with pd.option_context('display.max_rows', None, 'display.max_columns', None): for cluster, rows in df_feature.groupby('cluster'): print(f'\ncluster {cluster}:') for id in rows.index: print(track_info[id])
結果は以下の通り。
cluster 0:
ミックスナッツ - Official髭男dism
喜劇 - 星野 源
Habit - SEKAI NO OWARI
FEARLESS - LE SSERAFIM
Dynamite - BTS
Butter - BTS
群青 - YOASOBI
一途 - King Gnu
常緑 - 大橋ちっぽけ
怪物 - YOASOBI
WA DA DA - Kep1er
The Feels - TWICE
Bye-Good-Bye - BE:FIRST
ELEVEN - IVE
cluster 1:
ベテルギウス - 優里
なんでもないよ、 - マカロニえんぴつ
水平線 - back number
残響散歌 - Aimer
STAY (with Justin Bieber) - The Kid LAROI|ジャスティン・ビーバー
Cry Baby - Official髭男dism
猫 - DISH//
I LOVE... - Official髭男dism
おもかげ (produced by Vaundy) - milet|Aimer|幾田りら
cluster 2:
M八七 - 米津玄師
ドライフラワー - 優里
カメレオン - King Gnu
シャッター - 優里
勿忘 - Awesome City Club
逆夢 - King Gnu
点描の唄 - Mrs. GREEN APPLE|井上苑子
魔法の絨毯 - 川崎 鷹也
YOKAZE - 変態紳士クラブ
ハート - あいみょん
Stand by me, Stand by you. - 平井 大
cluster 3:
W / X / Y - Tani Yuuki
シンデレラボーイ - Saucy Dog
CITRUS - Da-iCE
恋風邪にのせて - Vaundy
きらり - 藤井 風
LOVE DIVE - IVE
Permission to Dance - BTS
Mela! - 緑黄色社会
夜に駆ける - YOASOBI
三原色 - YOASOBI
115万キロのフィルム - Official髭男dism
ヨワネハキ - MAISONdes|和ぬか|asmi
Pretender - Official髭男dism
踊 - Ado
BOY - King Gnu
cluster 4:
踊り子 - Vaundy
さらに、特徴ごとにクラスター別の箱ひげ図を作成する。上記コードに以下を追記。
# 特徴別の箱ひげ図を作成 fig, ax =plt.subplots(len(df_feature.columns) - 1, 1, figsize=(12, 40), facecolor=(1, 1, 1)) for i, col_name in enumerate(df_feature): if col_name != 'cluster': sns.boxplot(x=df_feature[col_name], y=df_feature['cluster'], width=0.5, orient='h', ax=ax[i]) sns.swarmplot(x=df_feature[col_name], y=df_feature['cluster'], color="r", orient='h', dodge=True, ax=ax[i]) plt.tight_layout() plt.show()
結果は以下のような箱ひげ図が作成される。クラスター4に1曲だけ属する「踊り子」は、ほかの曲に比べてacousticness(アコースティック度)とinstrumentalness(ボーカルがない度合い)が高いことがわかる。
0 件のコメント:
コメントを投稿