Spotifyデータセットを使ってSpotifyの100年分の曲を分析してみた

#はじめに
KaggleのSpotifyデータセットを使用して色々と分析してみました。
他の方のコードを参考に色々といじってみたので
アウトプット用として始めて記事を投稿します。

使用環境
MacOS 
Python 3.8.10
JupyterLab 3.0.14
## 今回使用したデータ
[Spotify Dataset 1922-2021](https://www.kaggle.com/yamaerenay/spotify-dataset-19212020-160k-tracks)
100年分のデータがまとまっており、曲数も約60万件も含まれているデータです。
##インポート
まずは必要なライブラリのインポート。

```python3
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
%matplotlib inline
import seaborn as sns

from tqdm import tqdm 
import time
import datetime
```
##曲のデータをダウンロード
データは**tracks.csv**を使用します。

```python3
#曲名詳細
tracks = pd.read_csv("tracks.csv")
tracks.head(3)
```
|     | id                     | name                                | popularity | duration_ms | explicit | artists             | id_artists                 | release_date | danceability | energy | key | loudness | mode | speechiness | acousticness | instrumentalness | liveness | valence | tempo   | time_signature | 
| --- | ---------------------- | ----------------------------------- | ---------- | ----------- | -------- | ------------------- | -------------------------- | ------------ | ------------ | ------ | --- | -------- | ---- | ----------- | ------------ | ---------------- | -------- | ------- | ------- | -------------- | 
| 0   | 35iwgR4jXetI318WEWsa1Q | Carve                               | 6          | 126903      | 0        | ['Uli']             | ['45tIt06XoI0Iio4LBEVpls'] | 1922-02-22   | 0.645        | 0.445  | 0   | -13.338  | 1    | 0.4510      | 0.674        | 0.7440           | 0.151    | 0.127   | 104.851 | 3              | 
| 1   | 021ht4sdgPcrDgSk7JTbKY | Capítulo 2.16 - Banquero Anarquista | 0          | 98200       | 0        | ['Fernando Pessoa'] | ['14jtPCOoNZwquk5wd9DxrY'] | 1922-06-01   | 0.695        | 0.263  | 0   | -22.136  | 1    | 0.9570      | 0.797        | 0.0000           | 0.148    | 0.655   | 102.009 | 1              | 
| 2   | 07A5yehtSnoedViJAZkNnc | Vivo para Quererte - Remasterizado  | 0          | 181640      | 0        | ['Ignacio Corsini'] | ['5LiOoJbxVSAMkBS2fUm3X2'] | 1922-03-21   | 0.434        | 0.177  | 1   | -21.180  | 1    | 0.0512      | 0.994        | 0.0218           | 0.212    | 0.457   | 130.418 | 5              | 
|||||
| name | album      | artists        | release_date | length   | popularity | danceability<br>     | acousticness                   | energy             | instrumentalness       | mode        | liveness<br>         | loudness               | speechiness    | valence<br>          | tempo      | time_signature | 
| 曲名 | アルバム名 | アーティスト名 | リリース日   | 曲の長さ | 人気度     | ダンス度 0.0-1.0<br> | アコースティック度 0.0-1.0<br> | エネルギー 0.0-1.0 | インスト感 0.0-1.0<br> | 曲調を示す  | ライブさ 0.0-1.0<br> | 音の大きさ -60 〜 0 db | スピーチ度<br> | 曲のポジティブ度<br> | 曲のテンポ | 拍子           | 
曲ごとに色々なパラメーターが付与されています。
詳しくは、Spotifyドキュメントに書いてあります。
https://developer.spotify.com/documentation/web-api/reference/#objects-index
#曲のデータ分析を実践してみる
###データ整形
release_dateを年と月単位にして, 必要のないカラムを削除

```python3
tracks["release_date"] = pd.to_datetime(tracks["release_date"])
tracks["release_year"] = tracks["release_date"].dt.year
tracks["release_month"] = tracks["release_date"].dt.month
cols_to_drop = ["id","id_artists","release_date"]
tracks.drop(columns=cols_to_drop,inplace=True)
```
###人気アーティストTop20
```python3
tracks.groupby("artists")["popularity"].mean().sort_values(ascending = False).to_frame()[: 20].plot(kind="bar",figsize=(18,8),color="skyblue",rot=30,title="Popular Artists Best10")
```
![artists_rank_img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1631114/38964c77-0c68-d41d-ae5c-9b3106792e4b.png)

###特徴量の相関関係を可視化
```python3
tracks_df.drop(["explicit","key","explicit","mode","time_signature","release_month"],axis=1,inplace=True)
#corrメソッド = 各列の間の相関係数が算出される
corr = tracks_df.corr()
plt.figure(figsize=(14,8))
sns.heatmap(corr,annot=True,fmt='.2f',cmap='RdBu_r')
plt.savefig("corr_image")
plt.show()
```
![corr_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1631114/1517b011-9937-27d6-9abb-a59fb733da8b.png)
####この相関図から考えられること
- yearとpopularity 年数を重ねるごとに人気度が高い(最近の曲の方が評価する人が多い)
- enegyとloudness 音が大きいジャンルはfast, loud, noisyである可能性が高い
- yearとloundness & enegy ここ20年あたりのロックやHIPHOPの影響であると思う
- popularityとloundness & enegy 上がる曲が人気(必然的)
- acousticnessとloundness & enegy 落ち着いているためまあ分かる
- acousticnessとyear 年々アコースティックの曲が減っている？
- loundnessとinstrumentalness 負相関な理由は疑問(音の大きさは楽器に影響していない？)
 
###特徴量の年推移を比較した折線グラフ
```python3
features_to_plot = ['energy', 'acousticness','instrumentalness', 'speechiness',"danceability"] 
plt.figure(figsize=(14,8))
before = time.time()
for i in tqdm(features_to_plot):
    sns.lineplot(x="release_year",y=i,data=tracks)

plt.legend(features_to_plot)
plt.ylabel("value")
after = time.time()
print("it took {}".format(after - before))
```
![スクリーンショット 2021-07-26 2.20.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1631114/da2e9bd4-39a8-140b-cfd8-0f7fbbbbb2e8.png)
・1945年の終戦前ではジャズやブルース、ゴスペルの流行にともない
スピーチ度やアコースティック度、インスト感などが高い傾向があります。
・逆に1960年代のイギリスロックシーンなどが流行すると
曲の速さ,大きさ,うるささが高くなっています。
###各特徴量の年推移を折線グラフでまとめてみた
```python3
features_to_plot = [['danceability','energy','loudness'],['speechiness','acousticness','instrumentalness'],['liveness','valence','tempo']]
fig,axes = plt.subplots(3,3,figsize=(18,12))
before = time.time()
for i in tqdm(range(3)):
    for l in range(3):
        color = np.random.rand(3,)
        sns.lineplot(x="release_year",y=features_to_plot[i][l],data=tracks,ax=axes[i][l],color=color,ci=False)
plt.tight_layout()        
plt.show()
after = time.time()
print("it took {}".format(after - before))
```
![feauture_img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1631114/5b2abbb1-fe73-7448-bebe-87c65757c0ab.png)
### 各特徴別のartistランキング Top5
```python3
features_to_plot = [['danceability','energy','loudness'],['speechiness','acousticness','instrumentalness'],['liveness','valence','tempo']]
fig,axes = plt.subplots(3,3,figsize=(25,20))
before = time.time()
for i in tqdm(range(3)):
    for l in range(3):
        color = np.random.rand(3,)
        tracks.groupby("artists")[features_to_plot[i][l]].mean().sort_values(ascending = False).to_frame()[: 5].plot(kind="bar",ax=axes[i][l],color=color,rot=20,title="Top5 artists for {}".format(features_to_plot[i][l]))
   
plt.show()
plt.tight_layout()
after = time.time()
print("it took {}".format(after - before))
```
![genres_rank_img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1631114/5ce23a33-9177-5953-9cb0-033601b806c7.png)
アーティスト名が長くて収まりませんでした。見にくくてすみません。
#曲のジャンルを分析してみる
今度は曲のジャンルごとによる分析をしていきたいと思います。
データは**data_by_genres_o.csv**を使用します。
##ジャンルのデータをダウンロード
```python3
#ジャンル詳細
genres_detail = pd.read_csv("data_by_genres_o.csv")
genres_detail.head(3)
```
|     | mode | genres                 | acousticness | danceability | duration_ms  | energy   | instrumentalness | liveness | loudness   | speechiness | tempo      | valence  | popularity | key | 
| --- | ---- | ---------------------- | ------------ | ------------ | ------------ | -------- | ---------------- | -------- | ---------- | ----------- | ---------- | -------- | ---------- | --- | 
| 0   | 1    | 21st century classical | 0.979333     | 0.162883     | 1.602977e+05 | 0.071317 | 0.606834         | 0.3616   | -31.514333 | 0.040567    | 75.336500  | 0.103783 | 27.833333  | 6   | 
| 1   | 1    | 432hz                  | 0.494780     | 0.299333     | 1.048887e+06 | 0.450678 | 0.477762         | 0.1310   | -16.854000 | 0.076817    | 120.285667 | 0.221750 | 52.500000  | 5   | 
| 2   | 1    | 8-bit                  | 0.762000     | 0.712000     | 1.151770e+05 | 0.818000 | 0.876000         | 0.1260   | -9.180000  | 0.047000    | 133.444000 | 0.975000 | 48.000000  | 7   | 
###人気ジャンルTop15
HIPHOPやROCKなどの大元のジャンルからの派生ジャンルが多いため
聞いたことのないコアなジャンルばかりですね(･ ･;)

```python3
top_10_genres = genres_detail.sort_values(by="popularity",ascending= False).head(15)
plt.figure(figsize=(14,8))
plt.bar(top_10_genres["genres"],top_10_genres["popularity"])
plt.xlabel('Genre')
plt.ylabel('Popularity')
plt.xticks(rotation=20)
plt.title('Top10 of Genres for popularity')
```
![genres_rank_img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1631114/47813094-eb30-d520-f801-c494f23eb08d.png)
###各特徴別のgenresランキング Top5
例のごとく各特徴量ごとの人気ジャンルを順位付けしていきます。

```python3
features_to_plot = [['danceability','energy','loudness'],['speechiness','acousticness','instrumentalness'],['liveness','valence','tempo']]
fig,axes = plt.subplots(3,3,figsize=(25,20))
before = time.time()
for i in tqdm(range(3)):
    for l in range(3):
        color = np.random.rand(3,)
        genres_detail.groupby("genres")[features_to_plot[i][l]].mean().sort_values(ascending = False).to_frame()[: 5].plot(kind="bar",ax=axes[i][l],color=color,rot=20,title="Top5 artists for {}".format(features_to_plot[i][l]))
        
plt.show()
plt.tight_layout()
after = time.time()
print("it took {}".format(after - before))
```
![any_genres_rank.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1631114/93541f9f-46f8-b754-c502-c238bb8d6e5c.png)
##多く作曲されている主要ジャンルを分析
派生ジャンルとしてとても細かいジャンルまであるので
ROCKやHIPHOPといった主要なジャンルとして分けたいと思います。
####ジャンルのみリスト化
```python3
main_name_genres = genres_detail["genres"].to_list()
main_name_genres[:5]
//['21st century classical', '432hz', '8-bit', '[]', 'a cappella']
```
####ワードごとに分割
'21st century classical'が**21st, century, classical**と3分割されました

```python3
main_name_genres = " ".join(genres_detail["genres"].to_list()).split()
main_name_genres[:5]
//['21st', 'century', 'classical', '432hz', '8-bit']
```
####ワードの出現回数を取得
collectionsモジュールを使用してそれぞれのワードの出現回数を
collections.Counter型(タプル型)として取り出しリスト化する

```python3
import collections

genres_tuple = collections.Counter(main_name_genres)
genres_list = list(genres_tuple.items())
genres_list[:5]
//[('21st', 2), ('century', 2), ('classical', 106), ('432hz', 1), ('8-bit', 1)]
```
####データフレーム化
参考にしたサイトです
https://www.delftstack.com/ja/howto/python-pandas/pandas-create-dataframe-from-list/

```python3
main_genres = pd.DataFrame(genres_list, columns = ['genres','count'])
main_genres.sort_values('count',ascending=False,inplace=True)
main_genres.reset_index(drop=True).head()
```
|  | genres | count |
| - | - | - |
| 0 | pop | 240 |
| 1 | indie | 237 |
| 2 | rock | 183 |
| 3 | metal | 132 |
| 4 | classical | 106 |
###主要ジャンル出現回数を可視化
```python3
df = main_genres.head(25)
plt.figure(figsize=(10,6))
sns.barplot(x='count' , y ='genres', data=df)
plt.title('主要ジャンル出現回数ランキング')
plt.ylabel('ジャンル名')
plt.xlabel('出現回数')
plt.show
```
![main_genres_rank.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1631114/d0ea7a7e-bdae-689a-2554-2ba9bf4e8021.png)
pop, indie, rock, metal, classicalという結果になりました。日本の歌は割と多いみたいです。
###上位４つの主要ジャンルから人気派生ジャンルを検証
特に作曲回数の多いpop, indie, rock, metalの人気派生ジャンルを7つ順位付けしました。
参考にしたサイトです https://note.nkmk.me/python-pandas-str-contains-match/

```python3
# https://note.nkmk.me/python-pandas-str-contains-match/
pop_df = genres_detail[genres_detail["genres"].str.contains("pop")].sort_values("popularity",ascending=False).head(7)
indie_df = genres_detail[genres_detail["genres"].str.contains("indie")].sort_values("popularity",ascending=False).head(7)
rock_df = genres_detail[genres_detail["genres"].str.contains("rock")].sort_values("popularity",ascending=False).head(7)
metal_df = genres_detail[genres_detail["genres"].str.contains("metal")].sort_values("popularity",ascending=False).head(7)

fig, axes = plt.subplots(2,2,figsize=(16,10))
axes[0,0].barh(width=pop_df['popularity'],y=pop_df['genres'],color="blue")
axes[0,1].barh(width=indie_df['popularity'],y=indie_df['genres'],color="green")
axes[1,0].barh(width=rock_df['popularity'],y=rock_df['genres'],color="orange")
axes[1,1].barh(width=metal_df['popularity'],y=metal_df['genres'],color="red")

fig.tight_layout(pad=1)
fig.show()
```
![sub_genres_rank.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1631114/a231e3f9-58ba-b059-2346-846d6ab59895.png)
やはり日本のジャンルは人気が高いみたいです。
個人的にkawaii metalがとても気になります(BABYMETAlLみたいな感じですかね？)
#まとめ
データ分析初心者としてデータ分析に必要なライブラリを使ってみて
知らない文法にも触れれてよかったです。
予想とは違った結果が多く、データ数も多い面白いデータセットだと思います。
機械学習に何か落とし込めないか模索していきます。