見出し画像

Spotifyで人気になる条件をPythonで分析した

こんなデータがありまして、遊んでみたわけで。

どんなデータか

以前、M-1グランプリで高得点とる漫才はどんな特徴か分析してみました。

今回は、Spotifyでヒット曲を作るにはどんな要素が必要か、みてみようと思います。

こんなデータです。

画像33

ID:ただの番号
TrackName:曲名
ArtistName:アーティスト名
Genre:曲のジャンル
Beats Per Minute:曲のテンポ
Energy:曲のエネルギー
Danceability:ダンスのしやすさ(値が大きいほど”躍りやすい曲”)
LoudnessdB:値が大きいほど、大声を出す曲
Liveness:値が大きいほど、ライブ録音に近い
Valence:値が大きいほど、ポジティブな曲
Length:曲の長さ
Acousticness:値が大きいほど、アコースティック
Speechiness:値が大きいほど、”語り”が曲の中にある
Popularity:曲の人気度

「ダンスのしやすさ」等、どうやってスコア化しているか分かりませんが、どんな要素が「Popularity(曲の人気度)」に大事か探索します。

先に結論でおま

「ポジティブで遅ぇ曲」か「ネガティブ(≒ポジティブじゃない)で速ぇ曲」が人気曲になりやすい
・具体的には「Valence 67.5以上、Beats Per Minute 95未満」「Valence 67.5未満、Beats Per Minute 99以上」の曲です

全米デビューを狙ってるそこのアナタの、ご参考になれば幸いです。

このあとは、↓のような集計・分析をしてます。

画像33

---✂︎---

♪人気の曲・歌手・ジャンル色々

まず、普通に人気TOP5みてみる

画像32

1、Billie Eilish - bad guy
2、Post Malone - "Goodbyes" ft. Young Thug (Rated R)
3、Callaíta - Bad Bunny
4、Drake - Money In The Grave ft. Rick Ross
5、Anuel AA - China

ジャンルは特に偏りがなさそう。

どんなアーティストが人気?

アーティスト別の曲数を集計して、ツリーマップにしてみました。

※ツリーマップってなに

画像32

EdSheeran兄貴が4曲リリースで一番多かったです。いつもありがとうございます。Shape of You です。

で、各曲の人気度をアーティスト別に集計してみると、

画像32

4曲リリースしているEdSheeran兄貴がぶっちぎりです。はい、Shape of You。

各曲の人気度の平均をアーティスト別に並べてみました。

画像8

Bad Bunny先輩Post Malone先輩が上位でした。

どんなジャンルが人気?

曲のジャンル別で集計してみました。

スクリーンショット 2020-01-01 16.42.47

ダンスポップが一番多くて、その次にポップ、ラテン、カナディアンヒップホップ。

もう少し大きなジャンルで「POP、HIP HOP、RAP、OTHER」で整理すると、こんな感じ。

スクリーンショット 2020-01-01 16.47.23

POPが大人気。

各曲の曲の人気度の平均をジャンル別に並べてみました。

画像8

「dfw rap」というジャンルが人気でした。次いで「trap music」。どちらも初めて聞いたジャンルです。

スクリーンショット 2020-01-01 17.02.20

Post Malone - "Goodbyes" ft. Young Thug (Rated R)
Lil Tecca - Ransom (Dir. by @_ColeBennett_)
Post Malone, Swae Lee - Sunflower (Spider-Man: Into the Spider-Verse)

1〜2曲だけなので、平均スコアでみるのはあまり相応しくないですね。

---✂︎---

♫人気曲の特徴

ってことで、人気曲(曲の人気度が高い)になる曲の特徴を探索してみようと思います。

♫平行座標でみてみる

パラレルコーディネートってやつです。なんかパターンや傾向はないかな、と。

スクリーンショット 2020-01-01 17.44.03

線の1本1本が一つのデータ(=1曲)で、赤い線ほど人気曲です。

・「語り」「ライブ録音感」はほとんどの曲で低い。
・「テンポが低め」「エネルギー高め」の曲が赤い線になってそう?
・「ダンスのしやすさ」も影響してそう?、、、って感じでしょうか。

🎶SpotifyのTOP50のデータ (1)

♫決定木でみてみる

続いて、決定木を作ってみます。曲の人気度(Popularity)を目的変数にした結果がコチラ。

スクリーンショット 2019-12-30 19.28.41

曲の人気度に対して、影響が大きい要素で分岐してます。

・まず初めの分岐は、Valence(曲のポジティブ度)です。
・次に、BeatsPerMinute(テンポ)です。

ノート編集|note (1)

♫グループ3
・まず「Valence 67.5以上、BPM95未満」の曲が最も人気が高いグループになりました。
・該当数は4曲

♫グループ2
・次に「Valence 67.5未満、BPM99以上」の曲が高かったです。
・該当数は22件

ってことで、「ポジティブで遅ぇ曲」か「ネガティブ(≒ポジティブじゃない)で速ぇ曲」、が人気になることが分かりました!(勢い)

全米デビューを狙ってるそこのアナタ、

「ポジティブで遅ぇ曲」
・「ネガティブで速ぇ曲」を、作りましょう♫

ご参考note

こちらのnoteではトレンドを網羅的にみられていて興味深かったです。

やり方でおま

このnoteでやった集計・分析の方法を下記してます。

画像31

ご自分でもやってみたい方はどうぞ。Pythonの初学者向けです。

Pythonを使って、
「ツリーマップ」が作成できるようになります
「平行座標」が作成できるようになります
「決定木分析」が出来るようになります

特に「決定木分析」は、マーケティングのお仕事をされてる方には便利です。

1:分析環境の構築

まず、分析環境の構築です。分析には、「Jupyter Notebook」を使います。

コチラのnoteの前半の無料部分の「◆まず、環境の準備です」をご覧ください。

2:ツリーマップの作り方

「Jupyter Notebook」の環境が整いましたでしょうか。

ここでは、以下のような「ツリーマップ」を作成します。

画像16

2−1:使用するライブラリのimport

#いつもの
import pandas as pd
import numpy as np

#これでtreemapが作成できます
import plotly.graph_objects as go

#この後に使用するので先にimportしておきます
import plotly
import plotly.express as px
※No module named 'xxx'、が出てきた際は、コチラのnoteの前半の無料部分の「◆「plotly」という便利なライブラリをインストールします」をみて、必要なライブラリをinstallしてください。

2−2:入れ子構造の理解

まず、サンプルで以下を実行してみましょう。

#サンプルです
fig = go.Figure(go.Treemap(
   labels = ["日本","関東","関西","九州","東京都", "大阪府", "京都府", "福岡県", "熊本県", "千葉県", "千代田区","足立区", "上京区","四国"],
   parents = ["","日本","日本","日本", "関東", "関西", "関西", "九州", "九州", "関東", "東京都","東京都", "京都府","日本"],
   values = [300,200,130,110,100,70,60,60,50,100,80,20,60,100]
))

fig.show()

スクリーンショット 2020-01-01 23.51.58

こんな感じで出てきます。引数に「labels」「parents」「values」があって、それぞれ以下となります。

特に、parentsという引数がどういう役割かを、↓の説明と↑のサンプルで理解できれば、もうこっちのもんです。

labels;
ツリーマップにしたい全要素の文字列をリスト型で入れます
parents;
labelsの入れ子構造の"親"になる要素をlabelsの中から指定します。一番上の枠に"親"は無いので、[""](=カラ)にします。
values;
labelsの値です。

2−3:この3つの引数に入れるだけ

データを読み込みます

df = pd.read_csv("/Users/[ディレクトリ]/top50.csv",encoding = "ISO-8859-1")

#列名を扱いやすいようにする
df.rename(columns={"Unnamed: 0":"ID"}, inplace=True)

df.rename(columns=lambda x : str(x).replace(".",""), inplace=True)

list型の変数を用意します

#Genreで、groupbyしたデータフレームを作成します
gb_genre =df.groupby("Genre").count()

#labelsに入れる要素を格納します
genre = list(gb_genre.index)

#valuesに入れる値を格納します
score = list(gb_genre.Popularity)

#確認
print(genre, len(genre))
print(score, len(score))

スクリーンショット 2020-01-02 15.19.03

あとは、3つの引数に"list型"入れるだけです。

また、paretnsは使用しないこともできます。まずは、parentsを使用せずにやってみます(その際は、labelsの要素分だけカラのlistを入れます)。

test_tree = go.Figure(go.Treemap(
   labels =  genre,
   #parentsは、なにか指定しないと出力されないので、空のリストをlabels要素分だけ用意します
   parents=[""]*len(genre),
   values =  score,#labelsの要素に対応する値をいれる
   textinfo = "label+value",
))


#html形式でエクスポートしたいとき
#plotly.offline.plot(test_tree, filename='treemap.html')

#描画
test_tree.show()

スクリーンショット 2020-01-01 16.31.56

「marker_colorscale = 'Reds'」という引数を設定すると色を変えることができます。

test_tree_color = go.Figure(go.Treemap(
   labels =  genre,
   #parentsは、なにか指定しないと出力されないので、空のリストをlabelsに入れた分だけ用意します
   parents=[""]*len(genre),
   values =  score,#labelsの要素に対応する値をいれる
   textinfo = "label+value",
   marker_colorscale = 'Reds'
))

#html形式でエクスポートしたいとき
#plotly.offline.plot(test_tree_color, filename='treemap.html')

#出力
test_tree_color.show()

スクリーンショット 2020-01-01 16.42.47

※「Reds」の所は「Greens、Blues、Greys、Purples」とか設定できます。

画像20

2−4:親(parents)要素を設定する

親ラベルを設定したツリーマップを作成します。

このデータではそのまま使えそうなのが無いので、元データを少々加工します。

#Genreをさらに大きなジャンルに変えるために関数を定義します
def test_func(str):
   if "pop" in str:
       return "POP"
   elif "hiphop" in str:
       return "HIP HOP"
   elif "rap" in str:
       return "RAP"
   else:
       return "OTHER"
#文字列を入れて、POP、HIP HOP、RAP、OTHERを返します
test_func("awefahiphopwoefoawfewaofawoe")

'HIP HOP'と、出力されるはずです。これをGenre列の値に実行します。

#Genre列の各行に先ほどの関数を実行
test_df = df.Genre.map(lambda x : test_func(x))

#確認
test_df.head()

#元のデータフレームに追加します
df["big_genre"] = test_df

#確認
df.big_genre.unique()

array(['POP', 'OTHER', 'RAP', 'HIP HOP'], dtype=object)

#新しく作ったbig_genreという列でgroupbyします
gb_big_genre =df.groupby("big_genre")

#リストに入れます
big_genre = list(gb_big_genre.count().index)
big_score = list(gb_big_genre.count().Popularity)

#確認
print(big_genre,big_score)
#一番初めに作ったリストに追加します
genre.extend(big_genre)
score.extend(big_score)

#確認
print(genre,score)

これで、「labels」と「values」に入れるリストが用意できました。最後に「parents」に入れるリストを作成します。

#Genreでgroupbyしたデータフレームのindex部分に先ほどの関数を実行してPOP、HIP HOP、RAP、OTHERに分けます
#それをlist方で格納します
parent = list(gb_genre.index.map(lambda x : test_func(x)))

#確認
print(parent)
print("---")
print(len(parent))
#四つの親ラベル分のカラのリストを追加します
big_parent = [""]*4

#追加します
parent.extend(big_parent)

#確認
print(parent)

これで準備完了です。以下を実行してください。

#グラフ生成
test_tree_3 = go.Figure(go.Treemap(
  labels =  genre,
  parents = parent,
  values = score,#labelsの要素に対応する値をいれる
  textinfo = "label+value",
  marker_colorscale = 'Reds'
  
))

#描画
test_tree_3.show()

スクリーンショット 2020-01-02 13.46.02

※"marker_colorscale = 'Reds'の部分を消したり、色を変えたりできます。

作成したグラフはhtml形式でエクスポートすることも可能です。

#グラフのエクスポート
plotly.offline.plot(test_tree_3, filename='treemap.html')

---✂︎---

もし、うまくいかない時は、コチラを実行ください↓。

いずれにせよ「labels」「parents」「values」の3つに同じ長さのlistを設定すればOKです。

#うまくいかない人はコチラ

#グラフ生成
test_tree_4 = go.Figure(go.Treemap(
  labels =  ['atlhiphop', 'australianpop', 'bigroom', 'boyband', 'brostep', 'canadianhiphop', 'canadianpop', 'countryrap', 'dancepop', 'dfwrap', 'edm', 'electropop', 'escaperoom', 'latin', 'panamanianpop', 'pop', 'pophouse', 'r&benespanol', 'reggaeton', 'reggaetonflow', 'trapmusic', 'HIP HOP', 'OTHER', 'POP', 'RAP'] ,
  parents = ['HIP HOP', 'POP', 'OTHER', 'OTHER', 'OTHER', 'HIP HOP', 'POP', 'RAP', 'POP', 'RAP', 'OTHER', 'POP', 'OTHER', 'OTHER', 'POP', 'POP', 'POP', 'OTHER', 'OTHER', 'OTHER', 'RAP', '', '', '', ''],
  values =  [1, 1, 1, 1, 2, 3, 2, 2, 8, 2, 3, 2, 1, 5, 2, 7, 1, 1, 2, 2, 1, 4, 18, 23, 5],#labelsの要素に対応する値をいれる
  textinfo = "label+value",
  #marker_colorscale = 'Reds'
  
))

#描画
test_tree_4.show()

---✂︎---

ツリーマップは以上です。ジャンルだけでなく、アーティスト名を入れてもいいですね。

スクリーンショット 2020-01-01 16.17.51


3:平行座標の作り方

続いて、平行座標です。コチラは、めちゃくちゃ簡単です。

ここから先は

4,223字 / 9画像
この記事のみ ¥ 300

貴重なお時間で読んでいただいてありがとうございます。 感謝の気持ちで、いっPython💕