47
34

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Spotify APIを使って曲のデータ分析をしてみる

Posted at

背景

音楽ストリーミングサービス「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

事前準備

  1. Spotifyのアカウントを作成します。

  2. Spotify for Developerにログインします。

  3. 右上のアカウントアイコンから、ダッシュボードを開きます。

  4. Create Appからアプリを作成します。

    アプリ名と説明は任意、Redirect URIsはリダイレクト先のURLを設定してください。

  5. 作成したアプリをダッシュボードから選択し、Settingボタンから設定画面を開きます。

    クライアントIDとクライアントシークレットが表示されるので、メモしておきましょう。

  6. 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ファイルを見てみると、ちゃんとデータ取得できているぽいです。
image.png

データを分析する

先ほど取得したCSVファイルを使ってデータを分析してみます。
パラメータ同士の関連性がレコメンド機能の実装に役立つかも?と思い、とりあえず相関分析からやってみることにしました。

以下のサイトを参考にしました。

pandasのcorrメソッドで相関係数を算出し、データを可視化するライブラリseabornを用いてヒートマップで表示します。

data_analytics.py
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()

こちらを動かしてみると…
下のようなヒートマップを作成できました!

Figure_1.png

正の相関があれば赤く、相関が無ければ白、負の相関があれば青くなっています。
画像を見てみると、いろいろなことが分かるようになりました。

まずは正の相関から。
valence(曲の陽性度)とdanceability(ダンスへの適応度)が0.7、energy(エネルギッシュさ)とloudness(音の大きさ)が0.6と強い相関を示しています。
ダンスに適してる曲は基本的に明るい・楽しい曲ですし、エネルギッシュな曲は音が大きいことも納得できます。

次に負の相関を見てみます。
danceability(ダンスへの適応度)とloudness(音の大きさ)、danceability(ダンスへの適応度)とtempo(BPM)が-0.5と強い負の相関を示しています。
ダンスに適している曲は音が小さく、テンポが遅い傾向があるということですね。
音が小さいのはあまり納得できないですが、テンポが速すぎる曲は踊ることに適していないのは確かです。

Spotify公式のヒットチャート(日本TOP50)でもヒートマップを作成してみます。

Figure2.png

正の相関について見てみると、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のプレイリストからデータを取得し、パラメータの相関分析を行うことが出来ました。
相関分析の結果としては、プレイリスト単位での傾向は知ることが出来ました。しかし、自分の趣味のプレイリストとヒットチャートの結果を見て分かる通り、分析対象によってかなり結果が変わってきます。
相関分析でパラメータの類似性が分かればいいな~と思っていたのですが、そもそものデータの傾向が分析結果に大きく影響するようです。
音楽のジャンルがバラバラ」「分析対象のデータ数が足りない」ことが思った通りに行かなかった原因でしょうか。。。

次は、ジャンル別で規模を大きくしたデータセットを作成し、もう一度データを分析してみようと思います。

つづく

47
34
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
47
34

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?