EDA Spotify Personal Data

Understanding Personal Music Taste with Spotify Personal Data

Moch Shandy Tsalasa Putra
Data Folks Indonesia
13 min readAug 11, 2021

--

EDA 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.

https://support.spotify.com/us/article/data-rights-and-privacy-settings/

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.jsonterlebih dahulu. Sebelum itu, kita perlu inisialisasi library yang dibutuhkan.

Import Library

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.

Decode JSON function

Oke, langsung kita coba masukin data nya ke function decode_JSON() dan ini hasilnya.

data = decodeJSON('MyData/YourLibrary.json')
Hasil decode data 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'])
Hasil JSON bentuk DataFrame
Nice

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())
List Artist

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.

Filter by Artist function

Explore ‘Cash Cash’ Data

df_cash = filterByArtist(df_nested_list, 'Cash Cash')
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'])
Cash Cash sort by album values

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'])
Cash Cash data with MultiIndex

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.

Track Count function

Setelah itu kita aplikasikan ke data kita dan berikut adalah hasilnya.

count_cash = track_count(df_cash)
Count Tracks by Each Album

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'])
Avicii

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)
Avicii Grouping
Count Tracks by Each Album

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')
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)
Hasil Translate

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)
Count Track by Each Album

Explore ‘Architects’ Data

df_archi = filterByArtist(df_nested_list, 'Architects')
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)
Count Track by Each Album

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')
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)
Hololive Idol Project Translate

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)
Hololive Grouping
Count Tracks by Each Album

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)
Wrap all Track Count

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'])
Data Podcast

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.

Streaming History

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'))
Streaming History Dataframe

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']
Streaming Data 2020

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")
Artists 2020

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, ]
Top 20 Artists 2020

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()
Visualization Top 20 Artists 2020

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']
Streaming Data 2021

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")
and many more…

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, ]
Top 20 Artists 2021

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()
Top 20 Artists 2021

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.

Kenny Omega (Orang WWE) pun main game ini😂

Conclusion

Job done

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.

--

--