Spotifyで人気になる条件をPythonで分析した
こんなデータがありまして、遊んでみたわけで。
どんなデータか
以前、M-1グランプリで高得点とる漫才はどんな特徴か分析してみました。
今回は、Spotifyでヒット曲を作るにはどんな要素が必要か、みてみようと思います。
こんなデータです。
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以上」の曲です
全米デビューを狙ってるそこのアナタの、ご参考になれば幸いです。
このあとは、↓のような集計・分析をしてます。
---✂︎---
♪人気の曲・歌手・ジャンル色々
♪まず、普通に人気TOP5みてみる
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
ジャンルは特に偏りがなさそう。
♪どんなアーティストが人気?
アーティスト別の曲数を集計して、ツリーマップにしてみました。
EdSheeran兄貴が4曲リリースで一番多かったです。いつもありがとうございます。Shape of You です。
で、各曲の人気度をアーティスト別に集計してみると、
4曲リリースしているEdSheeran兄貴がぶっちぎりです。はい、Shape of You。
各曲の人気度の平均をアーティスト別に並べてみました。
Bad Bunny先輩、Post Malone先輩が上位でした。
♪どんなジャンルが人気?
曲のジャンル別で集計してみました。
ダンスポップが一番多くて、その次にポップ、ラテン、カナディアンヒップホップ。
もう少し大きなジャンルで「POP、HIP HOP、RAP、OTHER」で整理すると、こんな感じ。
POPが大人気。
各曲の曲の人気度の平均をジャンル別に並べてみました。
「dfw rap」というジャンルが人気でした。次いで「trap music」。どちらも初めて聞いたジャンルです。
・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曲だけなので、平均スコアでみるのはあまり相応しくないですね。
---✂︎---
♫人気曲の特徴
ってことで、人気曲(曲の人気度が高い)になる曲の特徴を探索してみようと思います。
♫平行座標でみてみる
パラレルコーディネートってやつです。なんかパターンや傾向はないかな、と。
線の1本1本が一つのデータ(=1曲)で、赤い線ほど人気曲です。
・「語り」「ライブ録音感」はほとんどの曲で低い。
・「テンポが低め」「エネルギー高め」の曲が赤い線になってそう?
・「ダンスのしやすさ」も影響してそう?、、、って感じでしょうか。
♫決定木でみてみる
続いて、決定木を作ってみます。曲の人気度(Popularity)を目的変数にした結果がコチラ。
曲の人気度に対して、影響が大きい要素で分岐してます。
・まず初めの分岐は、Valence(曲のポジティブ度)です。
・次に、BeatsPerMinute(テンポ)です。
♫グループ3
・まず「Valence 67.5以上、BPM95未満」の曲が最も人気が高いグループになりました。
・該当数は4曲
♫グループ2
・次に「Valence 67.5未満、BPM99以上」の曲が高かったです。
・該当数は22件
ってことで、「ポジティブで遅ぇ曲」か「ネガティブ(≒ポジティブじゃない)で速ぇ曲」、が人気になることが分かりました!(勢い)
全米デビューを狙ってるそこのアナタ、
・「ポジティブで遅ぇ曲」か
・「ネガティブで速ぇ曲」を、作りましょう♫
ご参考note
こちらのnoteではトレンドを網羅的にみられていて興味深かったです。
やり方でおま
このnoteでやった集計・分析の方法を下記してます。
ご自分でもやってみたい方はどうぞ。Pythonの初学者向けです。
Pythonを使って、
・「ツリーマップ」が作成できるようになります
・「平行座標」が作成できるようになります
・「決定木分析」が出来るようになります
特に「決定木分析」は、マーケティングのお仕事をされてる方には便利です。
1:分析環境の構築
まず、分析環境の構築です。分析には、「Jupyter Notebook」を使います。
コチラのnoteの前半の無料部分の「◆まず、環境の準備です」をご覧ください。
2:ツリーマップの作り方
「Jupyter Notebook」の環境が整いましたでしょうか。
ここでは、以下のような「ツリーマップ」を作成します。
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()
こんな感じで出てきます。引数に「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))
あとは、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()
「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()
※「Reds」の所は「Greens、Blues、Greys、Purples」とか設定できます。
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()
※"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()
---✂︎---
ツリーマップは以上です。ジャンルだけでなく、アーティスト名を入れてもいいですね。
3:平行座標の作り方
続いて、平行座標です。コチラは、めちゃくちゃ簡単です。
貴重なお時間で読んでいただいてありがとうございます。 感謝の気持ちで、いっPython💕