Spotifyで自分が聞いた曲を分析してみた

## はじめに
Spotify便利ですよね。私はサービスを使うまではCD派だったんですが、Spotify使い始めてからというものの、すっかりサブスクすげええええってなってます。音楽の海を探検するのは楽しいです。もちろんCDでも聴いてますよ

このSpotify、再生した曲の履歴が昔は**50曲**しか残らなくて、去年の春くらいに３か月分残るようにアプデがあったんですけど、それでも履歴の検索は出来ないので、気軽に見返したりができないわけです。

そこで、Spotify APIを用いて再生楽曲をデータベースに保存するプログラムを作りました。で、かれこれ1年経ったので、自分が聴いてきた楽曲を分析してみました。

**[再生楽曲をデータベースに保存するプログラム](https://github.com/alrab223/Spotify_MusicSaver)**



このプログラム、ただ再生した楽曲を保存するのではなく、ちゃんと最初から最後まで再生した曲しか保存しないようになってます。何でかというと、間違えて再生した曲とか、ランダム再生でたまにスキップしたくなった時にその曲を除外するためです。イントロ飛ばしはゆるしまへんで！

## データについて
この一年で保存された楽曲数は18621曲でした。まあちゃんと再生してない曲しかカウントしてないのでこんなものでしょう。このデータベースには4つのテーブルがあります
* 楽曲データ
* アーティスト情報
* 楽曲の特徴
* 楽曲の人気度

これらをCSVに落として、データを見ていきます。今回使うのは楽曲の特徴ファイルだけです。

### 楽曲の特徴の内容
Spotify APIで得られる楽曲特徴データは様々あります。以下の表はデータベースで保存している特徴です。

|  特徴  |  説明  |
| ---- | ---- |
|  acousticness  |アコースティック度(0.0～1.0)|
|  danceability  |  踊りやすさ(0.0～1.0)  |
| energy |  エネルギッシュさ(0.0～1.0)  |
|  instrumentalness  |  インスト度(0.0～1.0)  |
|  key  |  曲のキー(0～11)  |
|  liveness  |  ライブ感(0.0～1.0) |
|  loudness  |  音量レベル(-60db～0db)  |
|  mode  |  調性(0,1)  |
|  speechiness   | しゃべりっぽさ(0.0～1.0)  |
|  tempo  |  テンポ(BPM)  |
|  valence  |  曲の明るさ(0.0～1.0)  |

このように、様々な特徴が取れます。
例えば`energy`はメタルとかハードロックだと高い数値が出るようです。`speechiness`は0.6あたりだとラップ曲といった感じです。
他の特徴はリファレンスを参照してください

https://developer.spotify.com/documentation/web-api/reference/#/operations/get-several-audio-features

## 楽曲分析
### APIを使う

では試しに1つの楽曲の特徴を見てみましょう。私の好きなフランツ・フェルディナンドの`Do You Want To`を分析してみます。

https://open.spotify.com/track/6WrnSlcN0dzTO80mVVbBto?si=aa0d2996d7b84b34

以下のプログラムを書きます。IDとかは各自で入手して入力してください。


```python
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
import pandas as pd
client_id = "xxx"
client_secret = "xxx"

client_credentials_manager = SpotifyClientCredentials(client_id, client_secret)
sp_body = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
track = sp_body.track("4ZdFTSdAmsoivF6pcM9Isz") #トラックID
print(track[9])
```

すると、以下の結果が得られる

```
{'danceability': 0.453,
 'energy': 0.477,
 'key': 2,
 'loudness': -8.364,
 'mode': 1,
 'speechiness': 0.032,
 'acousticness': 0.297,
 'instrumentalness': 0,
 'liveness': 0.193,
 'valence': 0.151,
 'tempo': 109.38,
 'type': 'audio_features',
 'id': '4ZdFTSdAmsoivF6pcM9Isz',
 'uri': 'spotify:track:4ZdFTSdAmsoivF6pcM9Isz',
 'track_href': 'https://api.spotify.com/v1/tracks/4ZdFTSdAmsoivF6pcM9Isz',
 'analysis_url': 'https://api.spotify.com/v1/audio-analysis/4ZdFTSdAmsoivF6pcM9Isz',
 'duration_ms': 237200,
 'time_signature': 4}
```

ざっと見ると、`energy`が高いですね。この曲はかなり陽気でノリノリな曲なので納得です。同様に`valence`も高く、この二つは似た属性なので相関がありそうです。
ただ、フランツ・フェルディナンドは踊れるロックということで定評があるのですが、`danceability`は思ったよりも高くありませんでした。EDMとかディスコとなるともう少し高くなるでしょうか

もう1曲特徴を見てみましょう。次はインスト曲のこれです。

https://open.spotify.com/track/3lpDrxUkr0tIe1kmJvdK7d?si=77a8f7668ec1441d

結果は以下のようになりました。
```
{'danceability': 0.51,
 'energy': 0.919,
 'key': 7,
 'loudness': -8.244,
 'mode': 1,
 'speechiness': 0.0593,
 'acousticness': 0.00205,
 'instrumentalness': 0.809,
 'liveness': 0.068,
 'valence': 0.386,
 'tempo': 141.053,
 'type': 'audio_features',
 'id': '3lpDrxUkr0tIe1kmJvdK7d',
 'uri': 'spotify:track:3lpDrxUkr0tIe1kmJvdK7d',
 'track_href': 'https://api.spotify.com/v1/tracks/3lpDrxUkr0tIe1kmJvdK7d',
 'analysis_url': 'https://api.spotify.com/v1/audio-analysis/3lpDrxUkr0tIe1kmJvdK7d',
 'duration_ms': 265840,
 'time_signature': 4}
```

インスト曲なので`instrumentalness`が0.809と高いですね。`danceability`がさっきよりも高いのが意外でした。

### 履歴を分析
それではマイソングス達を見ていきましょう。データベースからダンプした楽曲特徴データを掲載したCSVファイルの「music_features.csv」を使用します。
```
├── csv/
│   └─ music_features.csv
├── main.py
```


```main.py
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

df = pd.read_csv("csv/music_features.csv")
print(df)
```
実行するとこうなります。
```console:実行結果
       record_id                track_id  acousticness  danceability  energy  instrumentalness  key  liveness  loudness  mode  speechiness  tempo  valence
0              1  7f7qDb9gtih3uuSIiOk9Lv      0.000273         0.134  0.9800          0.000000  4.0    0.2170    -1.248   1.0       0.0846  167.0    0.719
1              2  1JNnJME8FBXASVWjDatyH3      0.000480         0.371  0.9010          0.000000  0.0    0.2830    -1.655   1.0       0.0616  127.0    0.661
2              3  7N3PAbqfTjSEU1edb2tY8j      0.171000         0.572  0.8350          0.000377  0.0    0.0702    -6.219   1.0       0.0317  129.0    0.795
3              4  0OLSKxtucXAdTRknBf3KbN      0.238000         0.591  0.9040          0.143000  0.0    0.1250    -6.021   1.0       0.0349  120.0    0.647
4              5  3aYVWpgxbah3J9RJXCWBJE      0.001840         0.538  0.8380          0.002910  2.0    0.1920    -6.126   0.0       0.0331  112.0    0.622
...          ...                     ...           ...           ...     ...               ...  ...       ...       ...   ...          ...    ...      ...
18616      18628  5Vj4eHzcf4SJNtOx2SxWxw      0.972000         0.389  0.0773          0.920000  4.0    0.0772   -22.129   1.0       0.0392  100.0    0.109
18617      18629  1GoANJKOliZEQqvkk9Mdvh      0.990000         0.483  0.3520          0.913000  4.0    0.1160   -17.332   1.0       0.0385   90.0    0.645
18618      18630  3lq6i23fC6j1v1AR0GeNg8      0.074700         0.648  0.8750          0.000096  2.0    0.1960    -5.141   0.0       0.0340  102.0    0.857
18619      18631  4TigEFb9C8CfKmzdJtgJ5f      0.066200         0.421  0.9290          0.000171  0.0    0.5010    -3.264   1.0       0.0485  123.0    0.758
18620      18632  0OLSKxtucXAdTRknBf3KbN      0.238000         0.591  0.9040          0.143000  0.0    0.1250    -6.021   1.0       0.0349  120.0    0.647
```

何かいろんな値が出てきましたね。。とりあえず`energy`でヒストグラムを出してみます。
```python
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
x = df["energy"]
ax.hist(x, bins="scott", range=(0, 1)) #スコットの選択
ax.set_title('energy histgram')
ax.set_xlabel('popularity')
ax.set_ylabel('frequency')
plt.xlim(0, 1)
plt.show()
```

![energy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/897435/629ef7dd-be88-1627-c3db-69a3df450eac.png)

HR/HMをよく聴くからでしょうか、エネルギッシュな曲が多いです。
他の特徴も見てみましょう。

![Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/897435/256ede1e-cb52-aa16-d85a-e2267f8a5dac.png)

曲の明るさ、アコースティック度、インスト度、踊りやすさ
4つのグラフを出力しました。インスト曲はもう少し聴いていたと思うのですがほとんどがボーカル曲であることが分かります。暗い曲から明るい曲まで幅広く聴いていますね。ロックに比重が傾くのでアコースティック度が低い曲に集中しているのは納得です。

![Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/897435/969b916e-d370-bbd4-dba5-378ae52f2a3c.png)
全てまとめるとこんな感じになります。ヒップホップとかラップはあんまり聴いてないのがばれてしまいました。

### 相関を調べる
次に、各特徴の相関を調べる。まずこの特徴群から相関がありそうなのは曲の明るさ`valence`と踊りやすさ`danceability`と考えられるので、散布図をプロットする。
```python
y = df["danceability"].values
print(np.corrcoef(x, y))
plt.xlabel("valence")
plt.ylabel("danceability")
plt.scatter(x, y, s=5)
plt.show()
```
![output.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/897435/800a5068-de0a-92a8-e28e-51621401fc6b.png)


このようにやや右肩上がりの散布図が出来上がりました。相関係数は0.6なのである程度の関係があるようですね。他のも見るためにヒートマップで相関係数をまとめてみました。
```python
import seaborn as sns

df = df.drop(columns='record_id')
df = df.drop(columns='track_id')
df_mean = (df - df.min()) / (df.max() - df.min()) #正規化
df_mean = df_mean.corr().round(2)
sns.heatmap(df_mean, cmap='coolwarm', vmin=-1, vmax=1, annot=True)
plt.show()
```
![heat_map.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/897435/400f8279-f7b9-22ef-74c0-b39743c72fd3.png)


特に相関係数が高いのが`energy`と`loudness`の0.87ですね。確かにエネルギッシュな曲は音量レベルを大きめに設定していることが多いので、納得できます。次に高いのが先述の`valence`と`danceability`で、三番目が`acosuticness`と`instrumentalness`でした。

`acosuticness`と`instrumentalness`はおそらく私がジャズをよく聞いてるため、このような結果が出たと思いますが、例えばフュージョンとかサントラをよく聞いている人はこの限りでないでしょう。

逆に、相関係数が低いのが`acosuticness`と`energy`,`loudness`、`instrumentalness`と`loudness`あたりです。`acosuticness`は明るい曲と逆になるのは納得できます。インスト曲はうるさい曲もありますが、私は基本ジャズを聴いているので負の相関となっています。メタルインストばっかり聴いてる人なら正の相関になるんじゃないでしょうか

## まとめ
こうやって分析していくと、その人がどんな音楽を聴いているのかが見えてきて面白いですね。そもそも私がデータベースに履歴を保存しようとしたのは、「普段どんな音楽聴いてるの？」という質問にデータを使って答えたかったからなんです。こういったデータは自己紹介とかのプレゼンで使用すれば面白そうだなと思うので、これからも色々と解析していきたいと思います。

ちなみに自分が聴いてる曲以外も解析したりしてますが、例えばヒットチャートの解析とかはもう既に何人かQiitaにも記事を上げてやってたりするので、私は音楽好きとしてちょっと趣向を凝らしたアプローチをしていきたいと思います。