EDA Spotify Personal Data
Understanding Personal Music Taste with Spotify Personal Data
Halo. Jadi ide project iseng ini itu muncul waktu aku iseng surfing di Reddit buat b̶u̶a̶n̶g̶ -̶ ̶b̶u̶a̶n̶g̶ ̶w̶a̶k̶t̶u̶ cari ide project sama cari berita apa yang lagi menarik.
Scrolling bagian home terus nemu thread yang menarik perhatianku, judulnya “Do any of you understand this inference label? Got it from Spotify inference data”. Baca — baca komennya pada jelasin apa itu maksud dari datanya, dsb. Terus tiba — tiba ada yang komen, “Loh, itu gimana cara dapetin datanya?” dan dijawab sama yang bikin thread itu “Langsung aja ke web nya Spotify terus request minta data nya”. Oke, langsung cus ke web nya buat minta data nya.
Ternyata nggak bisa langsung di download data nya, kudu nunggu up to 30 days buat Spotify gather data kita. “Waduuuhhh… lama juga ya”. Tapi tenang aja kok kita nggak perlu nunggu 30 hari buat nunggu data nya dari Spotify, cuma nunggu 3 hari udah langsung di email data nya.
Isi Data Personal Spotify
Buat yang penasaran isi data nya apa aja yang dikasih sama Spotify, ini list data nya:
- DuoNewFamily.json
- FamilyPlan.json
- Follow.json
- Inferences.json
- Payments.json
- Playlist1.json
- SearchQueries.json
- StreamingHistory0.json
- UserData.json
- YourLibrary.json
Buat detail isi data nya apa aja bisa cek langsung di web nya Spotify, udah lengkap banget jelasin isi nya apa aja dari masing — masing data itu. Buat di tulisan ini aku cuma bakalan explore data StreamingHistory0.json
dan YourLibrary.json
. Untuk data YourLibrary.json
itu isinya tentang summary dari content yang aku save atau masukin ke Library aku, mulai dari Songs, Artists, Albums, and Podcast) dan untuk data StreamingHistory0.json
itu isinya tentang list of items yang aku dengerin selama setaun kebelakang, seperti Date and time, artistName, albumName, dan berapa lama mili — seconds (yes, mili — seconds) buat tracks yang aku dengerin.
Explore the Data
Oke, kita mulai masuk ke bagian yang paling seru nih, yaitu explore data yang udah aku dapetin dari Spotify.
Buat yang pertama aku bakalan explore data YourLibrary.json
terlebih dahulu. Sebelum itu, kita perlu inisialisasi library yang dibutuhkan.
Karena data nya berupa nested JSON dan bentuknya berantakan, maka aku perlu decode terlebih dahulu JSON data nya agar bisa dibaca oleh pandas
. Pertama — tama, aku bakalan buat sebuah function buat decode JSON.
Oke, langsung kita coba masukin data nya ke function decode_JSON()
dan ini hasilnya.
data = decodeJSON('MyData/YourLibrary.json')
Setelah itu, aku bakalan masukin data decode JSON itu ke pandas
dan ternyata masih error juga.
ValueError: Invalid file path or buffer object type: <class 'dict'>
Haduh, ternyata masih error juga. Akhirnya cari — cari solusi gimana cara mengatasi error itu dan aku nemu Medium post yang bahas cara ngatasi error itu, yaudah langsung aja aku ̶c̶o̶p̶a̶s̶ pelajari code nya dan cara pakai nya. Dan hasilnya jadi seperti ini.
df_nested_list = pd.json_normalize(data, record_path =['tracks'])
Oke nice, kita udah bikin data nya jadi human readable. Di tahap ini aku bakalan drop column uri
karena menurutku nggak ada insight yang bakal aku dapat dari situ, karena uri
sendiri itu sifatnya unique untuk masing — masing value.
df_nested_list = df_nested_list.drop('uri', axis=1)
Cek Data Artists
Untuk ini aku bakalan cek artist yang aku masukin ke Library Spotify ku itu siapa aja dan dari situ kita udah dapet insight yang menarik nih, ternyata artist yang aku masukin ke Library itu mulai dari artist Barat, Korea, Jepang, dan Indonesia.
np.sort(df_nested_list['artist'].unique())
Setelah itu aku coba ambil sample lima data artist yang bakalan di explore lebih lanjut buat dapetin insight yang lebih dalem, dan lima artist yang beruntung buat dijadikan sample data adalah Cash Cash, Avicii, Creepy Nuts, Architects, dan Hololive Idol Project. Disini aku ngebuat sebuah function buat nge filter data nya berdasarkan nama artist.
Explore ‘Cash Cash’ Data
df_cash = filterByArtist(df_nested_list, 'Cash Cash')
Hmm… disini aku ngerasa agak aneh sama data nya, terutama di bagian column album
baris 1 sampai 3. Kenapa setelah album Blood, Sweat & 3 Years
terus ke album How to Love (ft. Sofia Reyes)
dan balik lagi ke album yang pertama. Untuk masalah ini cukup gampang buat mengatasinya, kita tinggal sorting aja berdasarkan value column album
dan hasilnya jadi begini.
df_cash = df_cash.sort_values(by=['album'])
Oke, udah dapet data nya sesuai dengan keinginanku tapi juga masih ada yang aneh sama data nya. Iya, di column artist
dan album
value nya redundant. Ada dua cara untuk mengatasi masalah redundant, bisa melakukan grouping menggunakan groupby
atau MultiIndex
. Untuk di tulisan ini aku bakalan pakai MultiIndex
biar hasilnya lebih bagus dan gampang untuk dibaca, buat yang belum tau MultiIndex
itu apa bisa baca di Medium post ini udah lengkap ada penjelasan dan tutorialnya.
multi_cash = df_cash.set_index(['artist', 'album', 'track'])
Hasilnya jauh lebih human readable dan mudah di interpretasikan jika dibandingkan dengan dataframe sebelumnya. Selain itu, kita juga bisa menghitung ada berapa banyak lagu yang di album tersebut. Disini aku membuat function untuk menghitung ada berapa banyak lagu di masing — masing album.
Setelah itu kita aplikasikan ke data kita dan berikut adalah hasilnya.
count_cash = track_count(df_cash)
Dari raw data Cash Cash
kita bisa mendapatkan insight, seperti berapa banyak track di masing — masing album. Proses selanjutnya kita tinggal implementasi code yang diatas ke masing — masing sample data.
Explore ‘Avicii’ Data
Pada data Avicii
aku menghadapi masalah yang sama seperti pada data sebelumnya, yaitu ada value yang tidak urut pada column album
. Solusinya tinggal kita sorting saja berdasarkan value album.
df_avicii = filterByArtist(df_nested_list, 'Avicii')
df_avicii = df_avicii.sort_values(by=['album'])
Setelah itu kita tinggal melakukan proses grouping dan menghitung track pada masing — masing album.
multi_avicii = df_avicii.set_index(['artist', 'album','track'])
count_avicii = track_count(df_avicii)
Explore ‘Creepy Nuts’ Data
Sekedar intermezzo aja, waktu pertama kali denger tentang artist ini agak aneh aja. Kalau diartikan ke Bahasa Indonesia artinya “Kacang Mengerikan”😂
Oke untuk proses nya sama seperti data — data sebelumnya.
df_creepy = filterByArtist(df_nested_list, 'Creepy Nuts')
Hooo? Ada yang menarik disini, yaitu untuk value column album
dan track
menggunakan Bahasa Jepang. Proses ini sebenarnya optional, boleh di translate menjadi Romaji agar teman — teman yang tidak bisa Bahasa Jepang bisa memahami dan membaca dari tulisan tersebut. Untuk itu kita bisa menggunakan function dari pandas
yaitu replace
. Pertama kita perlu melakukan .copy()
data kita terlebih dahulu, sebenarnya proses ini cukup krusial dan terkadang banyak orang yang melupakan proses ini. terkadang aku juga lupa. Alasan mengapa kita perlu .copy
bisa dibaca di postingan Stackoverflow ini.
df_creepy_tl = df_creepy.copy()# Proses mengganti value masing - masing column atau proses translate
df_creepy_tl['album'].replace({
'かつて天才だった俺たちへ':'Katsute Tensai datta Oretachi'
}, inplace=True)
df_creepy_tl['track'].replace({
'かつて天才だった俺たちへ':'Katsute Tensai datta Oretachi'
}, inplace=True)
Nice, sekarang teman — teman yang membaca tulisan ini bisa mengerti bagaimana cara membaca tulisan tadi. Karena data nya hanya ada satu record saja, maka tidak perlu dilakukan proses MultiIndex
tetapi disini aku hanya akan melakukan proses count track.
count_creepy = track_count(df_creepy_tl)
Explore ‘Architects’ Data
df_archi = filterByArtist(df_nested_list, 'Architects')
Karena record data nya hanya ada satu dan tidak perlu ada yang di translate, maka aku hanya akan melakukan proses track count.
count_archi = track_count(df_archi)
Explore ‘Hololive Idol Project’ Data
Fyuh… Akhirnya kita sudah sampai di sample data terakhir. Sekedar fun fact aja buat temen — temen yang nggak tahu, Hololive Production itu adalah sebuah agensi untuk talent Virtual Youtuber yang berasal dari Jepang dan biasanya “talent” dari agensi tersebut melakukan livestreaming layaknya Youtuber pada umumnya, seperti bermain game, bernyanyi, dsb dan pasarnya cukup rame di Indonesia, bahkan ada agensi Virtual Youtuber yang asli dari Indonesia yaitu MAHA5. So basically, Youtuber with Anime.
Anyway…
Untuk prosesnya sama seperti sebelumnya.
df_holo = filterByArtist(df_nested_list, 'hololive IDOL PROJECT')
Hmm… ternyata kita perlu melakukan proses translate menjadi Romaji karena ada record yang masih berbahasa Jepang. Untuk proses translate masih sama seperti data Creepy Nuts
.
df_holo_tl = df_holo.copy()
df_holo_tl['album'].replace({
'キラメキライダー☆':'Kirameki Rider',
'夢見る空へ':'Yumemiru Sora He'
}, inplace=True)
df_holo_tl['track'].replace({
'キラメキライダー☆':'Kirameki Rider',
'夢見る空へ':'Yumemiru Sora He'
}, inplace=True)
Apakah teman — teman notice ada yang aneh pada data tersebut? Ya, data tersebut ada yang duplicate pada column album
dan track
. Oleh karena itu kita perlu menghilangkan duplicate value tersebut dengan drop_duplicates()
dan caranya cukup pretty forward.
df_holo_tl.drop_duplicates(inplace=True)
Lalu kita lakukan proses grouping agar tidak terjadi redudancy pada column artist
dan proses track count.
multi_holo = df_holo_tl.set_index(['artist', 'album'])
count_holo = track_count(df_holo_tl)
Wrap Artist Sample Data
Pada bagian ini aku bakal melakukan wrap dengan cara menggabungkan semua data bagian track count menjadi satu dataframe.
# Create data secara manual
new_data = {
'Artist' : ['Cash Cash',
'Avicii',
'Creepy Nuts',
'Architects',
'Hololive Idol Project'],
'Total Lagu' : [16, 16, 1, 1, 4]
}total = pd.DataFrame(new_data)
total.sort_values('Total Lagu', ascending=False)
Cek Data Podcast
Untuk prosesnya sendiri sama seperti diatas. Tinggal memanggil hasil decode JSON tadi dan menggunakan pandas
dengan function json_normalize()
.
df_podcast = pd.json_normalize(data, record_path =['shows'])
Well, sebenernya dari sini udah keliatan sih insight nya kalau aku jarang dengerin Podcast. Karena data Podcast cuma ada dua records aja😂
Cek Streaming History Data
Oke sekarang kita masuk ke sesi explore streaming history data.
Menarik nih, bentuk data JSON nya ternyata berbeda dengan data YourLibrary.json.
Karena bentuk dari datanya cukup straight forward dan bukan nested list maka kita tinggal memanggil function read_json()
milik pandas
.
DATA_PATH = 'MyData/'
df_stream = pd.read_json(os.path.join(DATA_PATH, 'StreamingHistory0.json'))
Wow, ternyata datanya cukup detail, sepertiendTime
datanya berbentuk timestamp dan juga ada column msPlayed
yang menandakan aku untuk satu lagu itu memutar berapa milisecond. Untuk column endTime
ternyata oleh Spotify aku diberi data history streaming selama satu tahun kebelakang, oleh karena itu aku bakal filter datanya menjadi data tahun 2020 dan 2021.
Sebelum aku filter datanya, mari kita cari insight dari data ini. Disini aku bakal mencari insight berapa banyak Artists yang aku dengarkan selama tahun 2020 sampai 2021.
print(f"Total Unique Artist in 2020 - 2021 : {df_stream['artistName'].nunique()} Artists")
Total Unique Artists in 2020 — 2021 : 410 Artists
Wow ternyata cukup banyak😂
Lalu proses selanjutnya aku bakalan drop column msPlayed
karena hanya menunjukkan angka berapa milisecond aku mendengarkan lagu, mungkin di suatu saat aku bakal explore data itu, untuk bakal aku drop terlebih dahulu.
df_stream = df_stream.drop(['msPlayed'],axis=1)
Explore 2020
Untuk proses filter data 2020 cukup straight forward, aku hanya mengambil data yang value dari column endTime
kurang dari sama dengan2020-12-31
.
df_stream_2020 = df_stream[df_stream['endTime'] <= '2020-12-31']
Hmm, ternyata selama tahun 2020 aku mendengarkan sebanyak 993 lagu berdasarkan data yang diberikan oleh Spotify. Lalu seperti explore data Library diatas, aku ingin tahu siapa saja artist yang aku dengarkan pada tahun 2020 dan ada berapa banyak artistnya.
np.sort(df_stream_2020['artistName'].unique())
print(f"Total Unique Artist in 2020 : {df_stream_2020['artistName'].nunique()} Artists")
Total Unique Artists in 2020 : 111 Artists
Not bad… 111 artist yang aku play. Karena sebaran data artistnya mirip seperti pada data YourLibrary.json
yaitu ada artist dari Jepang, tentu saja kita bakal berhadapan lagi dengan proses translate nama artist menjadi Romaji. Untuk cara translate nya masih sama seperti yang diatas.
df_stream_2020_tl = df_stream_2020.copy()
df_stream_2020_tl['artistName'].replace({
'真島吾朗(宇垣秀成)': 'Goro Majima(Hidenari Ugaki)',
'星街すいせい': 'Hoshimachi Suisei',
'宝鐘マリン': 'Houshou Marine',
'美波': 'Minami',
'白上フブキ': 'Shirakami Fubuki'
}, inplace=True)
Oke setelah proses translate aku bakalan menghitung berapa banyak kemunculan artist ini pada tahun 2020 dengan value_counts()
dari pandas
dan setelah itu aku bakal mengambil Top 20 Artist di tahun 2020 dengan cara slicing.
counts_2020_tl = df_stream_2020_tl['artistName'].value_counts()
top_20_2020_tl = counts_2020_tl[:20, ]
Dari data Top 20 Artists kita bisa mengambil insight, ternyata ada empat artist yang ada di data sample Library diatas. Untuk artist yang paling sering aku stream pada tahun 2020 jatuh pada ASIAN KUNG-FU GENERATION, memang sih band itu temenin aku waktu lagi ngerjain tugas kuliah, nulis paper, kerjain project, dsb. Setelah itu data Top 20 Artists bakalan aku buat visualisasi datanya pakai library matplotlib
.
plt.figure(figsize=(10,7))
sns.barplot(top_20_2020_tl.index, top_20_2020_tl.values, alpha=0.8)
plt.title('Top 20 Artists in 2020')
plt.ylabel('How Many Times Scrobbled', fontsize=12)
plt.xticks(rotation=90)
plt.xlabel('Artist', fontsize=12)
plt.show()
Untuk persebaran genre music nya cukup diverse, tapi sayang Spotify tidak menyediakan data genre music per track nya. Jadi aku bakalan grouping Top 20 Artists 2020 secara manual saja dengan bantuan Google untuk mengetahui genre music dari masing — masing artists.
- Rock : ASIANG KUNG-FU GENERATION, Padi
- Hardcore : Crystal Lake, Architects, Bring Me The Horizon
- Pop : ZUTOMAYO, Aimer, Park Hyo Shin, Tia, Robokosan
- Alternative/Indie : Helsinki Lambda Club, EDEN
- EDM : Yunomi, Snail’s House, Avicii, Houshou Marine
- Hip — Hop/Rap : Laze, Creepy Nuts
- Dangdut : NDX A.K.A
- Idol : hololive IDOL PROJECT
Ternyata genre music yang aku dengerin pada tahun 2020 di dominasi oleh genre Pop sebanyak 5 artists.
Explore 2021
Untuk proses explore nya sama seperti pada data tahun 2020, kita filter berdasarkan tahun 2021 dimana pada kasus ini kita akan mengambil data endTime
yang lebih dari sama dengan 2021-01-01
.
df_stream_2021 = df_stream[df_stream['endTime'] >= '2021-01-01']
Wow… ternyata datanya jauh lebih banyak sekitar 3x lipat daripada data di tahun 2020👀
Lalu, kita akan explore untuk mengetahui siapa saja artist yang aku dengarkan dan ada berapa banyak. Untuk caranya sama seperti di data tahun 2020.
np.sort(df_stream_2021['artistName'].unique())
print(f"Total Unique Artist in 2021 : {df_stream_2021['artistName'].nunique()} Artists")
Total Unique Artists in 2021 : 337 Artists
Ternyata dari data streaming tahun 2021 yang sebanyak 2661, ada sebanyak 337 yang aku dengarkan pada tahun 2021👀. Padahal ini baru Agustus 2021 ketika aku menulis artikel ini, mungkin pada akhir tahun bisa menembus angka 500 artists👀
Proses selanjutnya ada translate nama artists dan mengambil Top 20 Artists 2021.
# Proses Translate
df_stream_2021_tl = df_stream_2021.copy()
df_stream_2021_tl['artistName'].replace({
'ハロー、ハッピーワールド!': 'Hello, Happy World!',
'宝鐘マリン': 'Houshou Marine',
'星街すいせい': 'Hoshimachi Suisei',
'猫又おかゆ': 'Nekomata Okayu',
'秋元薫': 'Kaoru Akimoto',
'花園たえ(CV.大塚紗英)': 'Tae Hanazono',
'香澄': 'Kasumi Toyama'
}, inplace=True)# Proses mengambil Top 20 Artists 2021counts_2021_tl = df_stream_2021_tl['artistName'].value_counts()
top_20_2021_tl = counts_2021_tl[:20, ]
Dari data Top 20 Artists 2021 kita bisa mengambil insight, untuk artist yang paling sering aku stream pada tahun 2021 jatuh pada SG Wannabe. Sebenernya ini bukan aku yang dengerin artist itu (loh). Karena di tahun 2021 aku share account sama kakak aku buat pake akun Spotify ini dan untuk menghemat biaya streaming platform lain. Jadi, kalau berdasarkan dari yang aku stream pada tahun 2021 untuk artist yang paling sering aku denger lagu nya jatuh pada PinocchioP. Lalu untuk proses selanjutnya ada membuat visualisasi data Top 20 Artists 2021.
plt.figure(figsize=(10,7))
sns.barplot(top_20_2021_tl.index, top_20_2021_tl.values, alpha=0.8)
# plt.stem(top_20_2020_tl.index, top_20_2020_tl.values)
plt.title('Top 20 Artists in 2021')
plt.ylabel('How Many Times Scrobbled', fontsize=12)
plt.xticks(rotation=90)
plt.xlabel('Artist', fontsize=12)
plt.show()
Oke, untuk selanjutnya kita bakalan melakukan grouping Top 20 Artists 2021 secara manual berdasarkan genre.
- Rock : ONE OK ROCK, Afterglow, Roselia
- Pop : SG Wannabe, Park Hyo Shin, YOASOBI, KYUHYUN, ZUTOMAYO, Poppin’Party, TUYU, Pastel*Palettes
- Jazz : Jacob Collier
- Vocaloid : PinocchioP, Neru
- EDM : Snail’s House
- Hip — Hop/Rap : Creepy Nuts, Hello Happy World, Eminem, Juice WRLD
- Idol : hololive IDOL PROJECT
Sama seperti data tahun 2020, genre Pop masih mendominasi di Top 20 Artists 2021, terdapat genre baru yang masuk pada list ini yaitu Jazz dan Vocaloid walaupun Vocaloid sendiri menurutku bukan genre sih, melainkan sebuah vocal synthesiser software. Tetapi daripada ribet untuk melakukan grouping nya maka aku jadikan sebuah genre saja hehe. Dan yang nggak aku sangka ternyata band Afterglow, Roselia, Poppin’Party, Pastel*Palettes, Hello Happy World bakalan masuk di list Top 20 Artists 2021. Buat yang nggak tahu, kelima band tersebut berasal dari sebuah game BanG Dream! Girls Band Party, basically game nya seperti Guitar Hero but in Anime version.
Conclusion
Selesai sudah perjalanan kita pada tulisan ini, dari dua data diatas kita bisa mendapatkan insight yang cukup banyak. Teman — teman bebas bisa melakukan apa saja dari Spotify Personal Data, code diatas bisa disesuaikan dengan data teman — teman jika ingin mencoba nya. Tetapi cukup disayangkan pada data tersebut kurang begitu detail kalau menurut aku, mungkin apabila ada data mengenai genre pada masing — masing tracks/artist bakal lebih banyak lagi yang bisa di explore untuk mengambil sebuah insight.
Code bisa diakses di Github.