Pendahuluan

Latar Belakang

Spotify adalah layanan music digital yang menyediakan akses untuk jutaan lagu dari berbagai artis di dunia. Oleh karena tersedia banyak lagu yang dapat diakses , dapat membuat kita binggung dalam memilih lagu yang ingin kita dengar.

Artikel ini akan membantu anda dalam mengcluster lagu-lagu sehingga dapat membantu pembaca dalam memilih lagu yang sesuai dengan kriteria yang kita inginkan

Data

Dekripsi Data :

Akustik: Apakah trek akustik (Nilai lebih tinggi trek akustik)

Danceability: Seberapa cocok lagu untuk berbasis menari (Nilai yang lebih tinggi adalah yang paling bisa menari)

Energi: Mewakili ukuran persepsi dari intensitas dan aktivitas (Musik death metal memiliki energi tinggi)

instrumentalness: Apakah sebuah lagu tidak mengandung vokal (Nilai yang lebih tinggi dari lagu tersebut adalah instrumental)

Kehidupan: Kehadiran penonton dalam rekaman (Lagu dibawakan secara langsung)

Kenyaringan: Tingkat kenyaringan keseluruhan trek dalam desibel (dB)

Kemampuan Berbicara: Kehadiran kata-kata yang diucapkan dalam sebuah trek (Trek mungkin berisi musik atau ucapan)

Valensi: Musik positif yang disampaikan oleh sebuah lagu (Lagu dengan valensi tinggi artinya bahagia atau ceria)

The data I get from Kaggle with this following link:

Kaggle

Persiapan

Package & Import Data

library(tidyverse)
library(FactoMineR)
library(factoextra)
data_spotify <- read.csv("SpotifyFeatures.csv")

Lagu Populer

popular_song <- data_spotify %>% filter(popularity >= 75)

Pemilihan angka 75 merupakan Subjektif, jadi bisa disesuai dengan angka yang teman-teman inginkan

Filter

Memilih variabel yang digunakan dengan tipe numerik / angka

data_clean <- popular_song %>% 
 select(c(acousticness,danceability,energy,instrumentalness,liveness,loudness,speechiness,valence))

head(data_clean)

Exploratory Data Analysis

Check Data

glimpse(data_clean)
## Rows: 3,593
## Columns: 8
## $ acousticness     <dbl> 0.023300, 0.422000, 0.544000, 0.619000, 0.031900, 0.0~
## $ danceability     <dbl> 0.845, 0.552, 0.515, 0.672, 0.731, 0.818, 0.559, 0.56~
## $ energy           <dbl> 0.709, 0.650, 0.479, 0.588, 0.861, 0.705, 0.345, 0.93~
## $ instrumentalness <dbl> 0.00e+00, 2.75e-04, 5.98e-03, 2.41e-01, 0.00e+00, 2.3~
## $ liveness         <dbl> 0.0940, 0.3720, 0.1910, 0.0992, 0.0829, 0.6130, 0.141~
## $ loudness         <dbl> -4.547, -7.199, -7.458, -9.573, -5.881, -6.679, -13.4~
## $ speechiness      <dbl> 0.0714, 0.1280, 0.0261, 0.1330, 0.0323, 0.1770, 0.045~
## $ valence          <dbl> 0.6200, 0.3160, 0.2840, 0.2040, 0.7800, 0.7720, 0.458~
anyNA(data_clean)
## [1] FALSE

Mantap!, Tidak ada data yang kosong.

summary(data_clean)
##   acousticness        danceability       energy       instrumentalness   
##  Min.   :0.0000183   Min.   :0.217   Min.   :0.0511   Min.   :0.0000000  
##  1st Qu.:0.0302000   1st Qu.:0.588   1st Qu.:0.5280   1st Qu.:0.0000000  
##  Median :0.1180000   Median :0.690   Median :0.6560   Median :0.0000000  
##  Mean   :0.2024467   Mean   :0.680   Mean   :0.6426   Mean   :0.0069187  
##  3rd Qu.:0.3070000   3rd Qu.:0.775   3rd Qu.:0.7690   3rd Qu.:0.0000332  
##  Max.   :0.9890000   Max.   :0.965   Max.   :0.9890   Max.   :0.9280000  
##     liveness         loudness        speechiness        valence      
##  Min.   :0.0215   Min.   :-22.320   Min.   :0.0228   Min.   :0.0352  
##  1st Qu.:0.0949   1st Qu.: -7.513   1st Qu.:0.0417   1st Qu.:0.3190  
##  Median :0.1200   Median : -5.934   Median :0.0676   Median :0.4840  
##  Mean   :0.1681   Mean   : -6.347   Mean   :0.1126   Mean   :0.4911  
##  3rd Qu.:0.2010   3rd Qu.: -4.706   3rd Qu.:0.1470   3rd Qu.:0.6570  
##  Max.   :0.8320   Max.   :  0.175   Max.   :0.6810   Max.   :0.9800
as.data.frame(var(data_clean))
plot(prcomp(data_clean))

Setelah nilai cek dan varians plot, kita dapat melihat rata-rata semua variabel adalah selisih dan variabel data varians kenyaringan memiliki sangat tinggi dibandingkan variabel lainnya.

Data dengan variabel perbedaan skala tinggi kurang baik untuk analisis clustering karena bersifat bias. Variabel akan dipertimbangkan untuk menangkap varian tertinggi dan variabel lain akan mempertimbangkan untuk tidak memberikan informasi.

Oleh karena itu, kita harus melakukan penskalaan sebelum melakukan clustering.

Scale

data_scale <- data_clean %>% scale() %>% as.data.frame()
summary(data_scale)
##   acousticness      danceability          energy         instrumentalness 
##  Min.   :-0.9176   Min.   :-3.32076   Min.   :-3.49675   Min.   :-0.1473  
##  1st Qu.:-0.7808   1st Qu.:-0.65987   1st Qu.:-0.67755   1st Qu.:-0.1473  
##  Median :-0.3828   Median : 0.07169   Median : 0.07912   Median :-0.1473  
##  Mean   : 0.0000   Mean   : 0.00000   Mean   : 0.00000   Mean   : 0.0000  
##  3rd Qu.: 0.4739   3rd Qu.: 0.68133   3rd Qu.: 0.74713   3rd Qu.:-0.1466  
##  Max.   : 3.5654   Max.   : 2.04405   Max.   : 2.04766   Max.   :19.6156  
##     liveness          loudness        speechiness         valence        
##  Min.   :-1.2151   Min.   :-6.5843   Min.   :-0.8859   Min.   :-2.06955  
##  1st Qu.:-0.6068   1st Qu.:-0.4807   1st Qu.:-0.6995   1st Qu.:-0.78120  
##  Median :-0.3988   Median : 0.1702   Median :-0.4441   Median :-0.03216  
##  Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.00000  
##  3rd Qu.: 0.2725   3rd Qu.: 0.6764   3rd Qu.: 0.3388   3rd Qu.: 0.75319  
##  Max.   : 5.5019   Max.   : 2.6884   Max.   : 5.6048   Max.   : 2.21950
var(data_scale)
##                  acousticness danceability      energy instrumentalness
## acousticness       1.00000000  -0.09576913 -0.50927988       0.06354763
## danceability      -0.09576913   1.00000000 -0.11096113      -0.05304323
## energy            -0.50927988  -0.11096113  1.00000000      -0.04490081
## instrumentalness   0.06354763  -0.05304323 -0.04490081       1.00000000
## liveness          -0.05826970  -0.02498200  0.11930980       0.05359032
## loudness          -0.39806260   0.03988425  0.72216648      -0.10517355
## speechiness       -0.07090832   0.29456501 -0.08833202      -0.07638406
## valence           -0.11123881   0.19362683  0.40562633      -0.08849891
##                     liveness    loudness speechiness     valence
## acousticness     -0.05826970 -0.39806260 -0.07090832 -0.11123881
## danceability     -0.02498200  0.03988425  0.29456501  0.19362683
## energy            0.11930980  0.72216648 -0.08833202  0.40562633
## instrumentalness  0.05359032 -0.10517355 -0.07638406 -0.08849891
## liveness          1.00000000  0.06423751  0.06311147  0.08597184
## loudness          0.06423751  1.00000000 -0.05822185  0.24135328
## speechiness       0.06311147 -0.05822185  1.00000000  0.03003683
## valence           0.08597184  0.24135328  0.03003683  1.00000000
plot(prcomp(data_scale))

Mantap!. Data siap diolah

PCA (Principal Component Analysis)

Fungsi Principal Component Analysis (PCA) adalah untuk mereduksi dimensi data tetapi tetap menyimpan informasi awal, dengan membuat sumbu baru yang dapat menangkap informasi sebanyak mungkin. Sumbu yang dibuat disebut Komponen Utama (PC), di mana sebagian besar informasi ditangkap oleh PC1, diikuti oleh PC2, PC3, PC4, dll

Membuat PCA

data_pca <- PCA(data_scale,scale.unit = F, graph = F)

Visualisasi

plot.PCA(data_pca,
         choix = "ind",
         select = "contrib 5",
         habillage = 1)

Dari plot yang diperlihatkan kita bisa melihat data outlier 477 , 1557 , 1582 , 2438 , 493

Variable Factor Map

Untuk melihat kontribusi variabel daru setiap pc, dan meilihat koerlasi antara variable

plot.PCA(data_pca, choix = "var")

fviz_contrib(X = data_pca,
             choice = "var",
             axes = 1)

fviz_contrib(X = data_pca,
             choice = "var",
             axes = 2)

Dari plot di atas, kita mendapatkan wawasan:

Dua variabel yang paling diringkas oleh PC1: energi & kenyaringan

Dua variabel yang paling diringkas oleh PC2: kemampuan menari & ucapan

Variabel dengan korelasi positif tinggi:

energi & kenyaringan

kemampuan menari & berbicara

Variabel dengan korelasi negatif tinggi:

energi & ucapan

kemampuan menari & kehidupan

Clulster / Pengelompokan

Mencari Nilai K Optimum

Sebelum kita melakukan analisis cluster, terlebih dahulu kita perlu menentukan jumlah cluster yang optimal. Dalam metode clustering, kami berusaha untuk meminimalkan jumlah kuadrat dalam cluster (artinya jarak antara observasi dalam cluster yang sama minimal). Untuk mendapatkan jumlah cluster yang optimal dapat digunakan 3 metode yaitu metode elbow, metode siluet, dan statistik gap. Tetapi disini kita akan menggunakan metode elbow

Memilih jumlah cluster menggunakan metode elbow adalah sewenang-wenang. Aturan praktisnya adalah kita memilih jumlah cluster di area “tikungan siku”, dimana grafik jumlah dalam jumlah kotak mulai stagnan dengan bertambahnya jumlah cluster.

RNGkind(sample.kind = "Rounding")
set.seed(417)
fviz_nbclust(data_scale, kmeans, method = "wss")

Dengan metode elbow, diketahui bahwa 8 cluster sudah cukup baik karena tidak ada penurunan yang signifikan dalam jumlah kotak dalam cluster pada jumlah cluster yang lebih banyak.

K-Mean Clustering

Berikut algoritma di balik K-Means Clustering:

Tetapkan nomor secara acak, dari 1 hingga K, untuk setiap pengamatan. Ini berfungsi sebagai tugas cluster awal untuk observasi. Iteratre sampai tugas cluster berhenti berubah. Untuk setiap cluster K, hitung pusat cluster. Centroid cluster K adalah vektor sarana fitur p untuk pengamatan pada cluster k. Tetapkan setiap observasi ke cluster yang sentroidnya paling dekat (menggunakan jarak euclidean atau pengukuran jarak lainnya)

RNGkind(sample.kind = "Rounding")
set.seed(417)

# k-means clustering
data_clust <- kmeans(data_clean, centers = 8)

Goodness of Fit

Hasil pengelompokan dapat dilihat dari 3 nilai Within Sum of Squares ($ withinss): jumlah jarak kuadrat dari setiap observasi ke centroid dari setiap cluster. Between Sum of Squares ($ betweenss): jumlah jarak kuadrat dari setiap sentroid ke rata-rata global. Berdasarkan jumlah observasi di cluster. Total Jumlah Kuadrat ($ tots): jumlah kuadrat jarak dari setiap pengamatan ke rata-rata global.

data_clust$withinss
## [1] 120.9976 191.9313 142.4012 211.1565 112.2179 178.3662 130.6765 166.0838
data_clust$betweenss
## [1] 20504.64
data_clust$totss
## [1] 21758.47

check ration clustering

((data_clust$betweenss)/ (data_clust$totss))*100
## [1] 94.2375
fviz_cluster(object=data_clust,
             data = data_clean,
             labelsize = 7)

popular_song$cluster <- data_clust$cluster

popular_song %>% 
  select(cluster, acousticness, danceability, energy, instrumentalness, liveness, loudness, speechiness, valence) %>% 
  group_by(cluster) %>% 
  summarise_all(mean)

Profiling:

Cluster 1: Lagu dengan banyak kemampuan menari dan energi, tetapi sedikit instrumental dan kenyaringan

Cluster 2: Lagu dengan banyak energi dan valensi, tetapi sedikit instrumental dan ucapan

Cluster 3: Lagu dengan banyak akustik dan instrumental, tetapi sedikit energi dan kenyaringan

Cluster 4: Lagu dengan banyak energi dan semangat, tetapi sedikit akustik dan instrumental

Cluster 5: Lagu dengan banyak instrumentalitas dan akustik, tetapi sedikit energi dan kenyaringan

Cluster 6: Lagu dengan banyak akustik dan kemampuan menari, tetapi sedikit bersemangat dan kenyaringan

Cluster 7: Lagu dengan banyak kemampuan menari dan ucapan, tetapi sedikit instrumentalitas dan valensi

Cluster 8: Lagu dengan banyak energi dan valensi, tetapi sedikit akustik dan instrumental

Lagu Rekomendasi

Example Case 1

popular_song %>% 
  filter(artist_name == "Linkin Park" & track_name == "Numb") %>% head(5)

Hasil dari artis “Linkin Park” dan nama lagu “Numb” kami memiliki 3 genre dengan cluster yang sama. Dari segi hasil clustering didapatkan hasil yang sama artinya 3 lagu tersebut berada pada cluster 3. Karena lagunya memiliki 3 genre, membuat Anda lebih memiliki pilihan untuk memilih genre yang ingin Anda dengar.

Misalnya, Anda memilih genre “Alternatif” dan musik apa yang selanjutnya akan disarankan?

popular_song %>% 
  filter(cluster == 3 & ï..genre == "Alternative") %>% head(5)

You can filter song with “cluster 3” and genre “Alternative”. After that you can see 5 song with similar taste and composition.

Contoh Kasus 22

Jika kamu sedang mendengarkan track “How Deep Is Your Love” dengan tempo lebih dari “100” tetapi belum tahu harus memilih musik selanjutnya setelah ini, model ini akan menunjukkan musik selanjutnya dengan komposisi dan rasa yang mirip.

popular_song %>% 
  filter(track_name == "How Deep Is Your Love" & tempo > 100)

Hasil dari track_name “How Deep Is Your Love” dan tempo lebih dari 100, kami punya 3 genre dengan cluster yang sama. Dari segi hasil clustering didapatkan hasil yang sama artinya 2 lagu berada pada cluster 8. Karena lagunya memiliki 2 genre, membuat Anda lebih memiliki pilihan untuk memilih genre yang ingin Anda dengar.

Misalnya, Anda memilih genre “Pop” dan musik apa yang selanjutnya akan disarankan?

popular_song %>% 
  filter(cluster == 8 & ï..genre == "Pop") %>% head() %>% as.data.frame()

Anda dapat memfilter lagu dengan “cluster 8” dan genre “Dance”. Setelah itu Anda bisa melihat 115 lagu dengan rasa dan komposisi yang mirip.

Kesimpulan

Dari analisis pembelajaran tanpa pengawasan di atas, dapat disimpulkan bahwa:

Reduksi dimensi dapat dilakukan dengan menggunakan dataset ini. Untuk melakukan reduksi dimensionalitas, kita dapat memilih PC dari total 8 PC sesuai dengan total informasi yang ingin kita simpan.

Kami dapat memisahkan data kami menjadi 8 cluster berdasarkan semua fitur numerik, dengan pengelompokan akurasi lebih dari 94,2%.