背景
音楽ストリーミングサービス「Spotify」にAPIがあることを知り、折角データが取れるのならデータ分析をしてみよう!と思い立ちやってみました。
(データ分析に関しては完全初心者なので、お試しでやってみたという記事です)
最終的には、Spotifyの自動レコメンド機能を自分で作ってみたいと考えています。。。
今回はプレイリストからデータ取得→相関分析まで行います。
内部パラメータについて
Spotify APIについて調べていくと、どうやら楽曲毎に以下のようなパラメータが付与されていることを知りました。
パラメータ | 説明 |
---|---|
acousticness |
曲がアコースティックである確率を0.0から1.0で表したもの。1.0は曲がアコースティックである確率が高いことを示す。 |
danceability |
曲がダンスに適しているかを0.0から1.0で表したもの。この値はテンポ、リズムの安定性、ビートの強さなどから計算され、1.0は曲がダンスに非常に適していることを示す。 |
energy |
曲がエネルギッシュである程度を0.0から1.0で表したもの。この値は活動的な音、速いテンポ、騒々しさなどから計算され、1.0は曲が非常にエネルギッシュであることを示す。 |
instrumentalness |
曲がインストゥルメンタルである確率を0.0から1.0で表したもの。1.0は曲がインストゥルメンタル(つまり、ボーカルなし)である確率が高いことを示す。 |
liveness |
曲がライブで演奏されている確率を0.0から1.0で表したもの。1.0は曲がライブで演奏されている確率が高いことを示す。 |
loudness |
曲の全体的な音の大きさをデシベルで表したもの。この値は曲全体にわたって平均化され、値は約-60から0dbまでの範囲である。 |
speechiness |
曲に話し言葉が含まれている確率を0.0から1.0で表したもの。1.0は曲が話し言葉で構成されている確率が高いことを示す。 |
valence |
曲が陽性の感情(例えば、幸せ、楽観的、陽気)を伝える確率を0.0から1.0で表したもの。1.0は曲が陽性の感情を強く伝えることを示す。 |
tempo |
曲の全体的な推定テンポをBPM(ビート・パー・ミニット)で表したもの。 |
key |
曲の全体的なキー(音階)を示す整数。この値はピッチクラス表記法によるもので、0 = C, 1 = C#/Db, 2 = D, と続く。 |
mode |
曲のモード(主音がメジャーかマイナーか)を示す整数。1はメジャー、0はマイナーを示す。 |
time_signature |
曲の拍子記号(1小節あたりの拍数)を示す整数。 |
かなりの量の属性情報があり、Spotifyのレコメンド機能はこのような値を使って実装されているのでは?と思いました。(このパラメータを利用すれば、自分でレコメンド機能を作成できそう…)
今回やること
内部パラメータの分析を行う
環境
使用言語はPython3.9、エディタはVSCodeを利用しています。
また、ライブラリとして以下のものを導入しています。
- Spotipy
- numpy
- pandas
- matplotlib
- seaborn
事前準備
-
Spotifyのアカウントを作成します。
-
Spotify for Developerにログインします。
-
右上のアカウントアイコンから、ダッシュボードを開きます。
-
Create Appからアプリを作成します。
アプリ名と説明は任意、Redirect URIsはリダイレクト先のURLを設定してください。
-
作成したアプリをダッシュボードから選択し、Settingボタンから設定画面を開きます。
クライアントIDとクライアントシークレットが表示されるので、メモしておきましょう。
-
spotipy
ライブラリを利用するので、pip等でインストールします。
データを取得する
とりあえず動かしてみます。
インポート
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials #ここ以降にいろいろ追加
APIレスポンスの中身が気になったのでほかにjson
とかpprint
とか入れてました。
必須情報
my_id = '発行したCLIANT ID'
my_secret = '発行したCLIANT SECRET'
Spotify for Developersから取ってきたものをつっこみます。
準備
ユーザー情報が必要ないメソッドを使う場合は、以下のコードでsp
からメソッドを呼び出せます。
ccm = SpotifyClientCredentials(client_id = my_id, client_secret = my_secret)
sp = spotipy.Spotify(client_credentials_manager = ccm)
ユーザー情報が必要な場合はOAuthで認証画面を表示する必要があります。以下のコードで実装できます。
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=my_id,
client_secret=my_secret,
redirect_uri="http://localhost:3000/",
scope="user-read-recently-played"))
スコープに欲しい情報の要素入れて、リダイレクト先で承認するフローを踏む必要があります。
redirect_uri
には事前準備で設定したリダイレクトURIを、scope
には利用したいメソッドで必要なものを入れます。
プレイリストから楽曲データを取得する関数
# プレイリストから曲を取得
def get_to_playlist(playlist_id):
playlist = sp.playlist(playlist_id)
track_ids = []
for item in playlist['tracks']['items']:
track = item['track']
if not track['id'] in track_ids:
track_ids.append(track['id'])
else:
for item in playlist['tracks']['items']:
track = item['track']
if not track['id'] in track_ids:
track_ids.append(track['id'])
return track_ids
プレイリストのIDを引数に、プレイリスト内の楽曲IDを配列に格納し返却します。
sp.playlist
にプレイリストIDを渡すと、プレイリストの情報がJSONで返ってくるので上手いこと抽出します。
楽曲の内部パラメータを取得する
audio_features
で内部パラメータを取得できます。
music_id = "楽曲のID"
result = sp.audio_features(music_id)
pprint.pprint(result)
こんな感じの情報が返ってきます。(サカナクション「忘れられないの」の場合)
[{'acousticness': 0.35,
'analysis_url': 'https://api.spotify.com/v1/audio-analysis/7a3LbQFgp7NCuNcGlTgSsN',
'danceability': 0.642,
'duration_ms': 238000,
'energy': 0.645,
'id': '7a3LbQFgp7NCuNcGlTgSsN',
'instrumentalness': 0.00349,
'key': 6,
'liveness': 0.191,
'loudness': -7.358,
'mode': 0,
'speechiness': 0.0375,
'tempo': 172.1,
'time_signature': 4,
'track_href': 'https://api.spotify.com/v1/tracks/7a3LbQFgp7NCuNcGlTgSsN',
'type': 'audio_features',
'uri': 'spotify:track:7a3LbQFgp7NCuNcGlTgSsN',
'valence': 0.917}]
関数にします。sp.track
で楽曲の基本データを、sp.audio_features
で内部パラメータを取得できます。
曲名、アルバム名、アーティスト名、尺と内部パラメータを気合で抽出し、配列にして返します。
def getTrackFeatures(id):
meta = sp.track(id)
features = sp.audio_features(id)
name = meta['name']
album = meta['album']['name']
artist = meta['album']['artists'][0]['name']
length = meta['duration_ms']
popularity = meta['popularity']
key = features[0]['key']
mode = features[0]['mode']
danceability = features[0]['danceability']
acousticness = features[0]['acousticness']
energy = features[0]['energy']
instrumentalness = features[0]['instrumentalness']
liveness = features[0]['liveness']
loudness = features[0]['loudness']
speechiness = features[0]['speechiness']
tempo = features[0]['tempo']
time_signature = features[0]['time_signature']
valence = features[0]['valence']
track = [name, album, artist, release_date, length, popularity, key, mode, danceability, acousticness,
energy, instrumentalness, liveness, loudness, speechiness, tempo, time_signature, valence]
return track
CSVファイルにデータを出力
データを扱いやすくするために一度CSV形式で出力します。
引数から得られた楽曲IDのリストから、楽曲の内部パラメータを取得する関数getTrackFeatures
を使って1曲ずつデータを取得します。
最後はpandasを使ってデータフレーム化し、to_csv
でcsvに変換します。
def id_to_csv(track_ids):
tracks = []
for track_id in track_ids:
track = getTrackFeatures(track_id)
tracks.append(track)
df = pd.DataFrame(tracks, columns=['name', 'album', 'artist', 'release_date', 'length', 'popularity', 'key', 'mode', 'danceability',
'acousticness', 'energy', 'instrumentalness', 'liveness', 'loudness', 'speechiness', 'tempo', 'time_signature', 'valence'])
df.head()
df.to_csv('myplaylist.csv', encoding='utf-8', index=False)
print("CSVファイルが作成されました。")
return df
動作確認
プレイリストIDを用意し、プレイリストから楽曲データを取得します。
そして楽曲データをCSVファイルに変換します。
今回使用したプレイリストは、私のSpotifyアカウントの自動レコメンドされたプレイリストです。
特徴としては、JPOPが多い、全50曲、インスト曲は少ないことが挙げられます。
if __name__ == '__main__':
ids = get_to_playlist("37i9dQZF1E39zhZzaOT7fU")
id_to_csv(ids)
動かしてみると、CSVファイルが作成されています。
> py my_top_song.py
CSVファイルが作成されました。
ExcelでCSVファイルを見てみると、ちゃんとデータ取得できているぽいです。
データを分析する
先ほど取得したCSVファイルを使ってデータを分析してみます。
パラメータ同士の関連性がレコメンド機能の実装に役立つかも?と思い、とりあえず相関分析からやってみることにしました。
以下のサイトを参考にしました。
pandasのcorr
メソッドで相関係数を算出し、データを可視化するライブラリseaborn
を用いてヒートマップで表示します。
import numpy as numpy
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
df_score = pd.read_csv(
'top50_japan_data.csv',
index_col= "name",
usecols=["name", "length", "popularity", "key", "mode", "danceability",
"acousticness", "energy", "instrumentalness", "liveness",
"loudness", "speechiness", "tempo", "valence"
])
df_corr = df_score.corr()
sns.set_context(context="talk")
fig = plt.subplots(figsize=(8, 8))
sns.heatmap(df_corr, annot=True, fmt='.1f', cmap='bwr', vmin=-1, vmax=1)
plt.show()
こちらを動かしてみると…
下のようなヒートマップを作成できました!
正の相関があれば赤く、相関が無ければ白、負の相関があれば青くなっています。
画像を見てみると、いろいろなことが分かるようになりました。
まずは正の相関から。
valence(曲の陽性度)とdanceability(ダンスへの適応度)が0.7、energy(エネルギッシュさ)とloudness(音の大きさ)が0.6と強い相関を示しています。
ダンスに適してる曲は基本的に明るい・楽しい曲ですし、エネルギッシュな曲は音が大きいことも納得できます。
次に負の相関を見てみます。
danceability(ダンスへの適応度)とloudness(音の大きさ)、danceability(ダンスへの適応度)とtempo(BPM)が-0.5と強い負の相関を示しています。
ダンスに適している曲は音が小さく、テンポが遅い傾向があるということですね。
音が小さいのはあまり納得できないですが、テンポが速すぎる曲は踊ることに適していないのは確かです。
Spotify公式のヒットチャート(日本TOP50)でもヒートマップを作成してみます。
正の相関について見てみると、energy(エネルギッシュさ)とloudness(音の大きさ)が0.8と非常に強い相関を示しています。
また、energy(エネルギッシュさ)とliveness(ライブ感)、speechiness(話し言葉の多さ)が0.5と強い相関を示しています。
最近の人気曲の傾向として、エネルギッシュな曲ほど音が大きく、ライブ感があり、話し言葉が多いことが分かります。
負の相関について見てみると、liveness(ライブ感)とdanceability(ダンスへの適応度)が-0.5と強い負の相関を示しています。
また、相関係数が-0.4の組み合わせは以下の通りでした。
- length(曲の長さ)とdanceability(ダンスへの適応度)
- length(曲の長さ)とvalence(曲の陽性度)
- energy(エネルギッシュさ)とacousticness(アコースティック度)
- tempo(BPM)とdanceability(ダンスへの適応度)
まとめ
Spotifyのプレイリストからデータを取得し、パラメータの相関分析を行うことが出来ました。
相関分析の結果としては、プレイリスト単位での傾向は知ることが出来ました。しかし、自分の趣味のプレイリストとヒットチャートの結果を見て分かる通り、分析対象によってかなり結果が変わってきます。
相関分析でパラメータの類似性が分かればいいな~と思っていたのですが、そもそものデータの傾向が分析結果に大きく影響するようです。
「音楽のジャンルがバラバラ」「分析対象のデータ数が足りない」ことが思った通りに行かなかった原因でしょうか。。。
次は、ジャンル別で規模を大きくしたデータセットを作成し、もう一度データを分析してみようと思います。
つづく