Pendahuluan

Dokumen ini bertujuan untuk melakukan analisis data pada dataset Ultimate Spotify Tracks DB. Proses analisisnya mencakup: - Preprocessing data - Pemilihan parameter - Visualisasi data

Persiapan Library

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.0.4     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(dplyr)
library(ggplot2)
library(cluster)      # Untuk clustering
library(factoextra)   # Untuk visualisasi clustering dan PCA
## Warning: package 'factoextra' was built under R version 4.4.3
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
library(readr)
library(corrplot)     # Untuk visualisasi korelasi
## corrplot 0.95 loaded
library(purrr)

Pembacaan Data

spotify <- read.csv("SpotifyFeatures.csv")
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 Willia…
## $ 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.00e+00, 0.00e+00, 0.00e+00, 0.00e+00, 1.23e-01, 0.0…
## $ 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…
summary(spotify)
##     genre           artist_name         track_name          track_id        
##  Length:232725      Length:232725      Length:232725      Length:232725     
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##    popularity      acousticness     danceability     duration_ms     
##  Min.   :  0.00   Min.   :0.0000   Min.   :0.0569   Min.   :  15387  
##  1st Qu.: 29.00   1st Qu.:0.0376   1st Qu.:0.4350   1st Qu.: 182857  
##  Median : 43.00   Median :0.2320   Median :0.5710   Median : 220427  
##  Mean   : 41.13   Mean   :0.3686   Mean   :0.5544   Mean   : 235122  
##  3rd Qu.: 55.00   3rd Qu.:0.7220   3rd Qu.:0.6920   3rd Qu.: 265768  
##  Max.   :100.00   Max.   :0.9960   Max.   :0.9890   Max.   :5552917  
##      energy         instrumentalness        key               liveness      
##  Min.   :2.03e-05   Min.   :0.0000000   Length:232725      Min.   :0.00967  
##  1st Qu.:3.85e-01   1st Qu.:0.0000000   Class :character   1st Qu.:0.09740  
##  Median :6.05e-01   Median :0.0000443   Mode  :character   Median :0.12800  
##  Mean   :5.71e-01   Mean   :0.1483012                      Mean   :0.21501  
##  3rd Qu.:7.87e-01   3rd Qu.:0.0358000                      3rd Qu.:0.26400  
##  Max.   :9.99e-01   Max.   :0.9990000                      Max.   :1.00000  
##     loudness           mode            speechiness         tempo       
##  Min.   :-52.457   Length:232725      Min.   :0.0222   Min.   : 30.38  
##  1st Qu.:-11.771   Class :character   1st Qu.:0.0367   1st Qu.: 92.96  
##  Median : -7.762   Mode  :character   Median :0.0501   Median :115.78  
##  Mean   : -9.570                      Mean   :0.1208   Mean   :117.67  
##  3rd Qu.: -5.501                      3rd Qu.:0.1050   3rd Qu.:139.05  
##  Max.   :  3.744                      Max.   :0.9670   Max.   :242.90  
##  time_signature        valence      
##  Length:232725      Min.   :0.0000  
##  Class :character   1st Qu.:0.2370  
##  Mode  :character   Median :0.4440  
##                     Mean   :0.4549  
##                     3rd Qu.:0.6600  
##                     Max.   :1.0000
# cek data NA
colSums(is.na(spotify))
##            genre      artist_name       track_name         track_id 
##                0                0                0                0 
##       popularity     acousticness     danceability      duration_ms 
##                0                0                0                0 
##           energy instrumentalness              key         liveness 
##                0                0                0                0 
##         loudness             mode      speechiness            tempo 
##                0                0                0                0 
##   time_signature          valence 
##                0                0
# cek data duplicated
sum(duplicated(spotify))
## [1] 0

Explorasi Data Awal

Distribusi Variabel Popularity

ggplot(spotify, aes(x = popularity)) +
  geom_histogram(binwidth = 5, fill = "steelblue", color = "white") +
  theme_minimal() +
  labs(title = "Distribusi Popularitas", x = "Popularity", y = "Frekuensi")

Insight: - Distribusi menunjukkan bahwa sebagian besar data cenderung pada nilai rendah ke tengah-tengah. - Kemungkinan terdapat outlier, terlihat dari adanya ekor pada sisi nilai yang lebih tinggi.

Visualisasi Korelasi antar Variabel Numerik

# Seleksi variabel numerik
numeric_vars <- spotify %>% 
  select(popularity, acousticness, danceability, duration_ms, energy, instrumentalness, 
         liveness, loudness, speechiness, tempo, valence)

# Visualisasi korelasi
corrplot(cor(numeric_vars), method = "color", addCoef.col = "black", tl.cex = 0.8)

Insight: - Hubungan kuat antara energy dan loudness. -> ini berarti lagu yang memiliki tingkat energi tinggi cenderung memiliki kekerasan (volume) yang tinggi juga. - Korelasi negatif antara accousticness dan energy. -> ini berarti lagu akustik memiliki tingkat energi rendah - Korelasi moderat antara danceability dan energy. -> ini berarti lagu yang ritme-nya cocok untuk dijadikan lagu tari, memiliki tingkat energi yang lebih tinggi.

Clustering dengan K-means

spotify_scaled <- scale(spotify %>% select(popularity, danceability, energy, valence))

# Menentukan jumlah cluster dengan metode elbow
wss <- function(k) {
  kmeans(spotify_scaled, centers = k, nstart = 10)$tot.withinss
}

# Hitung wss untuk k dari 1 sampai 10
k_values <- 1:10
wss_values <- map_dbl(k_values, wss)
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 11636250)
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 11636250)
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 11636250)
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 11636250)
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 11636250)
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 11636250)
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 11636250)
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 11636250)
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 11636250)
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 11636250)
## Warning: did not converge in 10 iterations
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 11636250)
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 11636250)
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 11636250)
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 11636250)
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 11636250)
# Plot metode elbow
plot(k_values, wss_values, type = "b", pch = 19, frame = FALSE,
     xlab = "Jumlah cluster (k)", ylab = "Total within Sum of Squares",
     main = "Metode Elbow untuk Menentukan k")

Insight: Berdasarkan bentuk grafik metode elbow tersebut, terlihat bawa “elbow point” atau “tekukan” terjadi saat k = 3. Setelah titik ini, penurunan Total within Sum of Squares mulai melambat, yang menunjukkan bahwa penambahan jumlah cluster setelah k = 3 tidak memberikan peningkatan yang signifikan dalam mengurangi varians internal.

Penerapan K-means

set.seed(123)
final_cluster <- kmeans(spotify_scaled, centers = 3, nstart = 25)
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 11636250)
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 11636250)
spotify$cluster <- as.factor(final_cluster$cluster)

# Visualisasi hasil clustering
fviz_cluster(final_cluster, data = spotify_scaled,
             geom = "point", ellipse.type = "convex",
             ggtheme = theme_minimal(),
             main = "Visualisasi Hasil Clustering K-Means")

Insight: - ketiga cluster terlihat cukup terpisah secara visual, walaupun ada sedikit overlapping di titik pertemuan antara cluster 1, 2, dan 3.

Principal Component Analysis (PCA)

pca <- prcomp(spotify_scaled, center = TRUE, scale. = TRUE)
summary(pca)
## Importance of components:
##                           PC1    PC2    PC3     PC4
## Standard deviation     1.4085 0.9773 0.8249 0.61700
## Proportion of Variance 0.4959 0.2388 0.1701 0.09517
## Cumulative Proportion  0.4959 0.7347 0.9048 1.00000
# visualisasi hasil PCA
pca_data <- as.data.frame(pca$x)
pca_data$cluster <- spotify$cluster

ggplot(pca_data, aes(x = PC1, y = PC2, color = cluster)) +
  geom_point(alpha = 0.6) +
  theme_minimal() +
  labs(title = "PCA Scatter Plot Berdasarkan Cluster",
       x = "Principal Component 1",
       y = "Principal Component 2")

Visualisasi PCA scatter plot menunjukkan bahwa lagu-lagu dalam dataset Spotify dapat dikelompokkkan ke dalam 3 cluster utama yang mempresentasikan karakteristik musik yang berbeda. Masing-masing cluster menunjukkan distribusi data lagu berdasarkan dua komponen utama hasil reduksi dimensi menggunakan PCA. 1. Cluster 1 (🟥) : lagu akustik / mellow - lagu-lagu dalam cluster ini cenderung memiliki tingkat energi dan kekerasan yang rendah, tapi akustiknya tinggi. - cluster ini kemungkinan berisi lagu-lagu ballad, singer-songwriter, atau folk acoustic yang lebih tenang dan tidak terlalu ritmis. 2. Cluster 2 (🟩) : lagu pop / mid-energy - lagu dalam cluster ini cenderung memiliki tingkat energi sedang dengan danceability yang tinggi. tapi tidak sekeras cluster 3. - cluster ini kemungkinan berisi lagu-lagu pop, R&B, chill, dan indie-pop. 3. Cluster 3 (🟦) : lagu energic / party - lagu-lagu dalam cluster ini cenderng memiliki tingkat energi dan kekerasan yang tinggi. - cluster ini kemungkinan terdiri dari EDM, hip-hop, trap, atau party music.