1 Import Library

library(dplyr)
library(GGally)
library(gridExtra)
library(factoextra)
library(FactoMineR)
library(plotly)

2 Case

Spotify adalah salah satu layanan streaming musik digital yang memberikan akses ke jutaan lagu di sekuruh dunia, pada penelitian ini bertujuan untuk melakukan klustering dan mengetahui fitur audio dominan di setiap klusternya dan melakukan reduksi dimensi data (PCA) dengan menganalisa pola untuk mendapatkan informasi dengan menggunakan 150 sample data lagu spotify

3 Read Data

spotify <- read.csv("SpotifyFeatures.csv")
head(spotify)
glimpse(spotify)
#> Rows: 232,725
#> Columns: 18
#> $ ï..genre         <chr> "Movie", "Movie", "Movie", "Movie", "Movie", "Movie",~
#> $ artist_name      <chr> "Henri Salvador", "Martin & les fées", "Joseph Willi~
#> $ track_name       <chr> "C'est beau de faire un Show", "Perdu d'avance (par G~
#> $ track_id         <chr> "0BRjO6ga9RKCKjfDqeFgWV", "0BjC1NfoEOOusryehmNudP", "~
#> $ popularity       <int> 0, 1, 3, 0, 4, 0, 2, 15, 0, 10, 0, 2, 4, 3, 0, 0, 0, ~
#> $ acousticness     <dbl> 0.61100, 0.24600, 0.95200, 0.70300, 0.95000, 0.74900,~
#> $ danceability     <dbl> 0.389, 0.590, 0.663, 0.240, 0.331, 0.578, 0.703, 0.41~
#> $ duration_ms      <int> 99373, 137373, 170267, 152427, 82625, 160627, 212293,~
#> $ energy           <dbl> 0.9100, 0.7370, 0.1310, 0.3260, 0.2250, 0.0948, 0.270~
#> $ instrumentalness <dbl> 0.00000000, 0.00000000, 0.00000000, 0.00000000, 0.123~
#> $ key              <chr> "C#", "F#", "C", "C#", "F", "C#", "C#", "F#", "C", "G~
#> $ liveness         <dbl> 0.3460, 0.1510, 0.1030, 0.0985, 0.2020, 0.1070, 0.105~
#> $ loudness         <dbl> -1.828, -5.559, -13.879, -12.178, -21.150, -14.970, -~
#> $ mode             <chr> "Major", "Minor", "Minor", "Major", "Major", "Major",~
#> $ speechiness      <dbl> 0.0525, 0.0868, 0.0362, 0.0395, 0.0456, 0.1430, 0.953~
#> $ tempo            <dbl> 166.969, 174.003, 99.488, 171.758, 140.576, 87.479, 8~
#> $ time_signature   <chr> "4/4", "4/4", "5/4", "4/4", "4/4", "4/4", "4/4", "4/4~
#> $ valence          <dbl> 0.8140, 0.8160, 0.3680, 0.2270, 0.3900, 0.3580, 0.533~

Deskripsi Data :

genre : Genre Musik
artist_name : Nama artis
track_name : Judul lagu
track_id : Id lagu
popularity : Kepopuleran lagu
acousticness : Tingkat keakustikan lagu
danceability : Tingkat ideal lagu untuk membuat pendengar menari
duration_ms : Durasi lagu dalam (milliseconds)
energy : Tingkat energi lagu
instrumentalness : Ragam instrumen yang dipakai dalam sebuah lagu
key : chord awal lagu dimulai
liveness : produksi musik dengan perandaian ketika lagu ditampilkan secara langsung
loudness : Tingkat kenyaringan lagu
mode : menggunakan nada yang sama dengan major standar namun dengan cara baru
speechiness ; Kerapatan kata dalm lagu
tempo : Tingkat cepat atau lambat sebuah lagu
time_signature : Birama
valence : Emosi yang dimunculkan sebuah lagu

4 Data Wrangling

spotify <- spotify %>% 
  mutate_at(vars(ï..genre,key,mode,time_signature),as.factor)
head(spotify)
names(spotify)[names(spotify) == "ï..genre"] <- "genre"
#check missing value
anyNA(spotify)
#> [1] FALSE
spotify <- spotify[1:150,]
#Mengambil data variabel numerik untuk melakukan scaling data
spotify_clean <- spotify%>% 
                 select_if(is.numeric)

head(spotify_clean)
summary(spotify_clean)
#>    popularity      acousticness      danceability     duration_ms     
#>  Min.   : 0.000   Min.   :0.00104   Min.   :0.1080   Min.   :  22413  
#>  1st Qu.: 0.000   1st Qu.:0.38900   1st Qu.:0.4440   1st Qu.: 144090  
#>  Median : 0.000   Median :0.66400   Median :0.5860   Median : 190034  
#>  Mean   : 7.767   Mean   :0.60700   Mean   :0.5647   Mean   : 253618  
#>  3rd Qu.: 3.000   3rd Qu.:0.85075   3rd Qu.:0.6837   3rd Qu.: 238110  
#>  Max.   :76.000   Max.   :0.98900   Max.   :0.9140   Max.   :3435625  
#>      energy        instrumentalness      liveness         loudness      
#>  Min.   :0.00154   Min.   :0.000000   Min.   :0.0320   Min.   :-25.274  
#>  1st Qu.:0.25350   1st Qu.:0.000000   1st Qu.:0.1090   1st Qu.:-14.343  
#>  Median :0.43800   Median :0.000000   Median :0.1460   Median :-10.709  
#>  Mean   :0.44017   Mean   :0.077886   Mean   :0.2026   Mean   :-11.158  
#>  3rd Qu.:0.63150   3rd Qu.:0.000202   3rd Qu.:0.2487   3rd Qu.: -7.503  
#>  Max.   :0.95300   Max.   :0.976000   Max.   :0.9000   Max.   : -1.828  
#>   speechiness         tempo           valence      
#>  Min.   :0.0258   Min.   : 32.24   Min.   :0.0378  
#>  1st Qu.:0.0370   1st Qu.: 90.24   1st Qu.:0.3615  
#>  Median :0.0557   Median :111.03   Median :0.5700  
#>  Mean   :0.1643   Mean   :113.94   Mean   :0.5468  
#>  3rd Qu.:0.1258   3rd Qu.:130.01   3rd Qu.:0.7478  
#>  Max.   :0.9610   Max.   :205.46   Max.   :0.9730
cov(spotify_clean[1:4])
#>                   popularity  acousticness  danceability      duration_ms
#> popularity       379.9250559   -1.54426447    0.45769351      -240084.730
#> acousticness      -1.5442645    0.08364705   -0.01681911         2209.618
#> danceability       0.4576935   -0.01681911    0.02834559         4115.406
#> duration_ms  -240084.7299776 2209.61750683 4115.40572036 145437758318.691

Dari hasil diatas variance dari masing-masing variabel berbeda jauh karena range/skala dari tiap variabel berbeda, begitupun covariance. Nilai variance dan covariance dipengaruhi oleh skala dari data. Semakin tinggi skala, nilai variance atau covariance akan semakin tinggi.

Scaling data

spotify_scale <- scale(spotify_clean) %>% 
  as.data.frame()
spotify_scale

5 Exploratory Data Analysis

ggcorr(spotify_scale,low = 'green', high = 'darkblue',
       label = TRUE, label_size = 2.5, hjust = 1, layout.exp = 3)

Analisa dari grafik korelasi diatas memberikan informasi bahwa ada beberapa variabel yang memiliki korelasi cukup kuat yaitu pada variabel energy dengan loudness, danceablility dengan valence dan energy dengan valence hal tersebut dapat diatasi dengan melakukan (PCA) agar menghilangkan sifat multikolinearitas pada data, dan mengunragi dimensi data tetapi dapat merangkum informasi sebanyak mungkin. Hasil dari analisis tersebut dapat dimanfaatkan untuk melakukan klasifikasi

6 Clustering

6.1 Mencari nilai K optimum

fviz_nbclust(spotify_scale, kmeans, method = "wss") + labs(subtitle = "wss method")

fviz_nbclust(spotify_scale, kmeans, "silhouette", k.max = 10) + labs(subtitle = "Silhouette method")

Berdasarkan dari analisis silhouette method dan wss K optimum berada di nilai 7, Maka cluster akan dibuat menjadi 7 kelas

7 K-Means Clustering

set.seed(100)
spotify_means <- kmeans(spotify_scale,7)

7.1 Interpretasi/Cluster Profiling

#memasukan label cluster ke data scale
spotify_scale$cluster <- as.factor(spotify_means$cluster)
head(spotify_scale)

7.2 CLuster Profiling

spotify_scale %>% 
  group_by(cluster) %>% 
  summarise_all(mean)

Dengan mengambil nilai rata - rata dari setiap kluster, sekarang kita dapat mengetahui karakteristik dari setiap kluster :
kluster 1 : lagu bersifat akustik, memiliki danceability untuk pendengar, durasi lagu rendah dan memiliki valence
kluster 2 : lagu memiliki popularity yang tinggi, tidak bersifat akustik, bersifat nyaring/loudness dan tempo cepat
kluster 3 : lagu bersifat akustik, memiliki dancebility yang rendah, bersifat instrumentalness
kluster 4 : lagu bersifat danceability serta memiliki durasi yang cukup lama serta bersifat speechiness
kluster 5 : lagu memiliki durasi yang rendah dan berenergy, dan memiliki liveness
kluster 6 : lagu tidak bersifat akustik, memiliki energy, loudness dan memiliki valence
kluster 7 : lagu bersifat akustik, dan memiliki tingkat valence yang rendah

#Visualisasi CLustering
fviz_cluster(object = spotify_means,
             data = spotify_scale[,-12])

8 PCA

pca <- spotify %>% 
  select_if(is.numeric)
pca$genre <- spotify$genre

PCA tidak hanya berguna untuk dimensionality reduction namun baik untuk visualisasi high-dimensional data. Visualisasi dapat menggunakan biplot yang menampilkan:

#Melakukan PCA dengan FactomineR
spotify_pca <- PCA(spotify_scale, quali.sup =12)

Dari grafik PCA diatas terbagi menjadi 2 PC, karena dari hasil reduksi dimensi tersebut PC 1 dan PC 2 akan merangkum informasi paling banyak, sehingga jika diaplikasikan kedalam biplot PC1 = sumbu x, sedangkan PC2 = sumbu y.

Insight :
- PC1 paling banyak merangkum variabel : acousticness,instrumentalness,danceability,valence,energy,loudness
- PC2 paling banyak merangkum variabel : speechiness,duration_ms,liveness,popularity,tempo

fviz_eig(spotify_pca, ncp = 10, addlabels = T, main = "Variance explained by each dimensions")

Jika dibuat kedalam grafik, dapat dibuktikan bahwa informasi paling tinggi berada di dimensi 1 dan 2 atau PC1 dan PC2

spotify_pca$eig
#>         eigenvalue percentage of variance cumulative percentage of variance
#> comp 1   3.2911084              29.919167                          29.91917
#> comp 2   1.8506667              16.824243                          46.74341
#> comp 3   1.1782375              10.711250                          57.45466
#> comp 4   1.0308187               9.371079                          66.82574
#> comp 5   0.8274323               7.522111                          74.34785
#> comp 6   0.7916284               7.196621                          81.54447
#> comp 7   0.7229491               6.572265                          88.11674
#> comp 8   0.5262140               4.783763                          92.90050
#> comp 9   0.3632822               3.302566                          96.20307
#> comp 10  0.2722207               2.474734                          98.67780
#> comp 11  0.1454421               1.322201                         100.00000
#Membuat data frame baru dari hasil PCA 
spotify_keep <- PCA(spotify_scale, graph = F, ncp = 6, quali.sup = 12)$ind$coord %>% as.data.frame()
spotify_x <- spotify_keep %>%
  bind_cols(cluster = as.factor(spotify_means$cluster))
head(spotify_x)

Dari hasil dimension reduction diatas mengambil 6 dimensi karena untuk mendaptkan informasi sebanyak 80%, yang didapatkan dari cummulative of percentage variance.

9 Observasi PCA

fviz_pca_ind(spotify_pca, habillage = 12, addEllipses = T)

Data outlier

spotify[c(16,55,97,115),]

Dari hasil diatas didapetkan bahwa data outlier dari genre movie, berada di cluster 4, sesuai dengan profiling kluster diatas, lagu outlier tersebut bersifat danceability serta memiliki durasi yang cukup lama serta bersifat speechiness yang tinggi.

spotify_viz <- spotify_keep %>%
  bind_cols(cluster = as.factor(spotify_means$cluster))
head(spotify_viz)

Menggunakan plotly untuk melihat visual data PCA dengan 3 Dimensi

plot_ly(spotify_viz, x = ~Dim.1, y = ~Dim.2, z = ~Dim.3, color = ~cluster, colors = c('black','blue',"yellow","green","red","magenta","brown")) %>%
  add_markers() %>% 
   layout(scene = list(xaxis = list(title = 'Dim.1'),
                     yaxis = list(title = 'Dim.2'),
                     zaxis = list(title = 'Dim.3')))

10 Kesimpulan

  1. Dari hasil analisis klustering didapatkan bahwa terdapat 7 kluster dengan karakteristiknya masing - masing, jika dilihat dari segi bisnis industri musik, lagu - lagu dengan tingkat populer yang tinggi berada di kluster 2 dengan karakter lagu tidak bersifat akustik dan memiliki tingkat kenyaringan yang tinggi dan memiliki tempo yang cepat

  2. Dalam melakukan reduksi dimensi kita dapat memilih semua PC, pada pemilihan nilai variabel PC diatas mengambil 6 variabel PC dengan mempertahankan 80% informasi dari data aslinya, yang dimana data tersebut dapat dilanjutkan dengan model supervised machine learning.