Dalam era digital saat ini, industri musik telah mengalami transformasi yang signifikan. Layanan streaming musik seperti Spotify telah menjadi platform populer bagi pengguna untuk menikmati musik favorit mereka. Dengan jutaan lagu yang tersedia, Spotify mengumpulkan data yang meliputi berbagai aspek dari setiap lagu, termasuk genre, artis, popularitas, akustik, danceability, energi, dan banyak lagi.
Dalam proyek ini, bertujuan untuk menganalisis data
Spotify
untuk mendapatkan wawasan yang berharga tentang
preferensi musik pengguna dan pola yang mungkin terkait dengan
fitur-fitur tertentu. Saya akan menerapkan teknik
unsupervised learning
untuk mengidentifikasi pola
tersembunyi dalam dataset dan menggunakan visualisasi untuk membantu
memahami data dengan lebih baik.
Laporan ini bertujuan untuk memberikan pemahaman yang komprehensif
tentang proses analisis data Spotify menggunakan teknik unsupervised
learning. Laporan ini akan menjelaskan langkah-langkah yang tepat yang
diambil untuk memproses data, memilih parameter yang sesuai, dan
menerapkan algoritma clustering
atau reduksi dimensi (PCA).
Selain itu, akan ada visualisasi sederhana untuk memberikan wawasan
tambahan yang berguna dalam menarik kesimpulan dari data Spotify yang
ada.
knitr::include_graphics("assets/spotfy.jpg")
Untuk memulai, kita perlu membaca data dari file CSV ke dalam sebuah
dataframe menggunakan fungsi read.csv()
.
data <- read.csv("data_input/SpotifyFeatures.csv")
glimpse(data)
#> 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…
genre
: Informasi tentang genre musik dari setiap
lagu.artist_name
:Berisi nama artis yang melakukan rekaman
lagu.track_name
: Menyimpan judul atau nama dari setiap
lagu.track_id
: Merupakan ID unik untuk setiap lagu dalam
data.popularity
: Tingkat popularitas lagu, dengan nilai yang
lebih tinggi menunjukkan popularitas yang lebih tinggi.acousticness
: Menunjukkan seberapa akustik suara lagu,
dengan nilai yang lebih tinggi menunjukkan lebih banyak unsur
akustik.danceability
: Mengindikasikan sejauh mana lagu cocok
untuk menari, dengan nilai yang lebih tinggi menunjukkan lagu yang lebih
mudah untuk diikuti irama.duration_ms
: Menyimpan durasi lagu dalam milidetik
(ms).energy
: Menggambarkan tingkat energi dan intensitas
suara lagu, dengan nilai yang lebih tinggi menunjukkan energi yang lebih
tinggi.instrumentalness
: Menunjukkan sejauh mana lagu bersifat
instrumental, dengan nilai yang lebih tinggi menunjukkan lebih sedikit
vokal dan lebih banyak unsur instrumental.key
: Merupakan kunci musik atau skala utama dari
lagu.liveness
: Mengindikasikan sejauh mana lagu terdengar
seperti rekaman langsung, dengan nilai yang lebih tinggi menunjukkan
elemen yang lebih hidup atau rekaman langsung.loudness
: Menggambarkan tingkat kebisingan atau volume
suara lagu dalam desibel (dB).mode
: Menyatakan apakah lagu tersebut dalam mode mayor
(Major) atau minor (Minor).speechiness
: Menunjukkan tingkat kehadiran unsur pidato
atau pengucapan kata dalam lagu, dengan nilai yang lebih tinggi
menunjukkan lebih banyak pengucapan kata daripada musik
instrumental.tempo
:Mengindikasikan kecepatan atau tempo musik dalam
ketukan per menit (BPM).time_signature
: Merupakan tanda waktu atau pola ritme
dalam lagu, seperti “4/4” yang menunjukkan pola ritmevalence
: Menggambarkan tingkat keceriaan atau
positivitas lagu, dengan nilai yang lebih tinggi menunjukkan lagu yang
lebih ceria atau positif.colSums(is.na(data))
#> 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
Insight
: Data yang kita punya tidak missing value.
library(dplyr)
data <- data %>%
select(-track_id) %>%
mutate(across(c(genre, popularity, key, mode, time_signature), as.factor))
summary(data)
#> genre artist_name track_name popularity
#> Comedy : 9681 Length:232725 Length:232725 0 : 6312
#> Soundtrack: 9646 Class :character Class :character 50 : 5415
#> Indie : 9543 Mode :character Mode :character 53 : 5414
#> Jazz : 9441 51 : 5401
#> Pop : 9386 52 : 5342
#> Electronic: 9377 49 : 5266
#> (Other) :175651 (Other):199575
#> acousticness danceability duration_ms energy
#> Min. :0.0000 Min. :0.0569 Min. : 15387 Min. :2.03e-05
#> 1st Qu.:0.0376 1st Qu.:0.4350 1st Qu.: 182857 1st Qu.:3.85e-01
#> Median :0.2320 Median :0.5710 Median : 220427 Median :6.05e-01
#> Mean :0.3686 Mean :0.5544 Mean : 235122 Mean :5.71e-01
#> 3rd Qu.:0.7220 3rd Qu.:0.6920 3rd Qu.: 265768 3rd Qu.:7.87e-01
#> Max. :0.9960 Max. :0.9890 Max. :5552917 Max. :9.99e-01
#>
#> instrumentalness key liveness loudness
#> Min. :0.0000000 C :27583 Min. :0.00967 Min. :-52.457
#> 1st Qu.:0.0000000 G :26390 1st Qu.:0.09740 1st Qu.:-11.771
#> Median :0.0000443 D :24077 Median :0.12800 Median : -7.762
#> Mean :0.1483012 C# :23201 Mean :0.21501 Mean : -9.570
#> 3rd Qu.:0.0358000 A :22671 3rd Qu.:0.26400 3rd Qu.: -5.501
#> Max. :0.9990000 F :20279 Max. :1.00000 Max. : 3.744
#> (Other):88524
#> mode speechiness tempo time_signature
#> Major:151744 Min. :0.0222 Min. : 30.38 0/4: 8
#> Minor: 80981 1st Qu.:0.0367 1st Qu.: 92.96 1/4: 2608
#> Median :0.0501 Median :115.78 3/4: 24111
#> Mean :0.1208 Mean :117.67 4/4:200760
#> 3rd Qu.:0.1050 3rd Qu.:139.05 5/4: 5238
#> Max. :0.9670 Max. :242.90
#>
#> valence
#> Min. :0.0000
#> 1st Qu.:0.2370
#> Median :0.4440
#> Mean :0.4549
#> 3rd Qu.:0.6600
#> Max. :1.0000
#>
Insight
: Perlu dilakukan scaling pada data yang ada,
agar variansnya sama
Pertama, kita akan menerapkan Principal Component Analysis (PCA) untuk reduksi dimensi. Hal ini dilakukan dengan tujuan mengurangi kompleksitas data dan mempertahankan informasi yang relevan.
Buat objek baru untuk analisis PCA, gunakan kolom yang bertipe numerik
data_pca <- data %>%
select_if(is.numeric)
plot(prcomp(data_pca))
Selanjutnya, kita perlu melakukan scaling pada data agar variabel memiliki skala yang sama. Hal ini penting karena beberapa variabel dalam data memiliki rentang nilai yang berbeda
data_scaled <- scale(data_pca)
summary(data_scaled)
#> acousticness danceability duration_ms energy
#> Min. :-1.0389 Min. :-2.68019 Min. :-1.8475 Min. :-2.1671
#> 1st Qu.:-0.9329 1st Qu.:-0.64310 1st Qu.:-0.4394 1st Qu.:-0.7058
#> Median :-0.3849 Median : 0.08963 Median :-0.1236 Median : 0.1292
#> Mean : 0.0000 Mean : 0.00000 Mean : 0.0000 Mean : 0.0000
#> 3rd Qu.: 0.9963 3rd Qu.: 0.74154 3rd Qu.: 0.2577 3rd Qu.: 0.8200
#> Max. : 1.7686 Max. : 2.34168 Max. :44.7114 Max. : 1.6247
#> instrumentalness liveness loudness speechiness
#> Min. :-0.4898 Min. :-1.0356 Min. :-7.1500 Min. :-0.53129
#> 1st Qu.:-0.4898 1st Qu.:-0.5932 1st Qu.:-0.3670 1st Qu.:-0.45314
#> Median :-0.4897 Median :-0.4388 Median : 0.3014 Median :-0.38091
#> Mean : 0.0000 Mean : 0.0000 Mean : 0.0000 Mean : 0.00000
#> 3rd Qu.:-0.3716 3rd Qu.: 0.2471 3rd Qu.: 0.6784 3rd Qu.:-0.08498
#> Max. : 2.8097 Max. : 3.9591 Max. : 2.2196 Max. : 4.56146
#> tempo valence
#> Min. :-2.82494 Min. :-1.74924
#> 1st Qu.:-0.79963 1st Qu.:-0.83793
#> Median :-0.06112 Median :-0.04198
#> Mean : 0.00000 Mean : 0.00000
#> 3rd Qu.: 0.69217 3rd Qu.: 0.78858
#> Max. : 4.05310 Max. : 2.09595
plot(prcomp(data_scaled))
pca <- prcomp(data_scaled)
Berikutnya, kita akan menggunakan PCA untuk mereduksi dimensi data. Kita dapat memilih jumlah dimensi yang ingin direduksi dan mempertahankan seberapa banyak informasi yang ingin kita pertahankan.
Case : Ingin merduksi 10 dimensi yang ada, dengan mempertahankan informasi yang ada.
#> Importance of components:
#> PC1 PC2 PC3 PC4 PC5 PC6 PC7
#> Standard deviation 1.8598 1.2736 1.0804 0.97566 0.89128 0.83406 0.7225
#> Proportion of Variance 0.3459 0.1622 0.1167 0.09519 0.07944 0.06957 0.0522
#> Cumulative Proportion 0.3459 0.5081 0.6248 0.72001 0.79945 0.86901 0.9212
#> PC8 PC9 PC10
#> Standard deviation 0.62911 0.52615 0.33951
#> Proportion of Variance 0.03958 0.02768 0.01153
#> Cumulative Proportion 0.96079 0.98847 1.00000
#> acousticness danceability duration_ms energy instrumentalness liveness
#> 1 0.6833748 -0.8909329 -1.1413655 1.2869052 -0.48981747 0.66065975
#> 2 -0.3454664 0.1919933 -0.8218657 0.6302479 -0.48981747 -0.32283477
#> 3 1.6445663 0.5852948 -0.5452965 -1.6699502 -0.48981747 -0.56492573
#> 4 0.9426992 -1.6936990 -0.6952933 -0.9297874 -0.48981747 -0.58762176
#> 5 1.6389288 -1.2034190 -1.2821808 -1.3131538 -0.08356631 -0.06561313
#> 6 1.0723614 0.1273410 -0.6263486 -1.8073548 -0.48981747 -0.54475148
#> loudness speechiness tempo valence
#> 1 1.2907007 -0.3679692 1.5956039 1.3807413
#> 2 0.6686811 -0.1830817 1.8232495 1.3884316
#> 3 -0.7184009 -0.4558311 -0.5883245 -0.3342114
#> 4 -0.4348159 -0.4380431 1.7505932 -0.8763826
#> 5 -1.9305971 -0.4051623 0.7414313 -0.2496173
#> 6 -0.9002886 0.1198533 -0.9769791 -0.3726633
#> PC1 PC2 PC3 PC4 PC5 PC6
#> 1 1.608076 0.01943355 0.2377522 2.0359381 -0.215300882 -0.1935772
#> 2 1.785895 -0.72321578 -0.2759833 1.5082760 -0.930143964 -0.0875709
#> 3 -1.672205 -0.10314197 -1.7397396 -0.2095422 -0.412506014 1.1438302
#> 4 -1.477940 -0.79746031 0.5679776 2.0632945 -0.434136141 1.3961619
#> 5 -2.503036 -0.06224634 -0.9024316 1.7928093 -0.480396112 0.6771452
#> 6 -1.777048 0.23939801 -1.6212937 -0.2843979 0.008036554 1.0854009
#> PC7 PC8 PC9 PC10
#> 1 -1.47148538 -0.88782639 1.14696819 0.09475008
#> 2 -0.39089788 -0.45548384 0.06303431 -0.07113580
#> 3 -0.12679229 0.42884934 0.56224901 -0.04344974
#> 4 -0.30266666 -0.47042801 0.14984911 -0.17574421
#> 5 -0.82964336 -0.20107899 -0.31772582 0.44803838
#> 6 0.06521505 0.08761386 -0.13223759 -0.38429350
pc_keep <- as.data.frame(pca$x[,1:4])
head(pc_keep)
#> PC1 PC2 PC3 PC4
#> 1 1.608076 0.01943355 0.2377522 2.0359381
#> 2 1.785895 -0.72321578 -0.2759833 1.5082760
#> 3 -1.672205 -0.10314197 -1.7397396 -0.2095422
#> 4 -1.477940 -0.79746031 0.5679776 2.0632945
#> 5 -2.503036 -0.06224634 -0.9024316 1.7928093
#> 6 -1.777048 0.23939801 -1.6212937 -0.2843979
Setelah tahapan ini, rangkum informasi yang dibutuhkan dengan menggabungkan data awal dengan variabel numerik awal.
head(data %>%
select_if(~!is.numeric(.)) %>%
cbind(pc_keep))
#> genre artist_name track_name popularity key mode
#> 1 Movie Henri Salvador C'est beau de faire un Show 0 C# Major
#> 2 Movie Martin & les fées Perdu d'avance (par Gad Elmaleh) 1 F# Minor
#> 3 Movie Joseph Williams Don't Let Me Be Lonely Tonight 3 C Minor
#> 4 Movie Henri Salvador Dis-moi Monsieur Gordon Cooper 0 C# Major
#> 5 Movie Fabien Nataf Ouverture 4 F Major
#> 6 Movie Henri Salvador Le petit souper aux chandelles 0 C# Major
#> time_signature PC1 PC2 PC3 PC4
#> 1 4/4 1.608076 0.01943355 0.2377522 2.0359381
#> 2 4/4 1.785895 -0.72321578 -0.2759833 1.5082760
#> 3 5/4 -1.672205 -0.10314197 -1.7397396 -0.2095422
#> 4 4/4 -1.477940 -0.79746031 0.5679776 2.0632945
#> 5 4/4 -2.503036 -0.06224634 -0.9024316 1.7928093
#> 6 4/4 -1.777048 0.23939801 -1.6212937 -0.2843979
Untuk lanjut ketahapan selanjutnya, perlu dilakukan pemisahan target variabel
library(GGally)
# Korelasi sebelum PCA
ggcorr(data, label = T, hjust =1)
#korelasi setelah PCA
ggcorr(data = pc_keep, label = T, hjust =1)
Setelah melakukan reduksi dimensi menggunakan PCA, kita dapat melihat
bahwa variabel-variabel dalam data terdistribusi dengan baik dalam ruang
dua dimensi. Hal ini menunjukkan bahwa fitur-fitur dalam data memiliki
kemampuan yang baik untuk membedakan lagu-lagu berdasarkan karakteristik
mereka.
Selanjutnya, kita akan menerapkan algoritma k-means untuk mengelompokkan lagu berdasarkan fitur-fiturnya. Kita perlu menentukan jumlah cluster yang optimal terlebih dahulu. Berikut adalah tahapan untuk menentukan jumlah cluster yang optimal:
library(cluster)
data_cluster <- data %>%
select_if(is.numeric)
head(data_cluster)
#> acousticness danceability duration_ms energy instrumentalness liveness
#> 1 0.611 0.389 99373 0.9100 0.000 0.3460
#> 2 0.246 0.590 137373 0.7370 0.000 0.1510
#> 3 0.952 0.663 170267 0.1310 0.000 0.1030
#> 4 0.703 0.240 152427 0.3260 0.000 0.0985
#> 5 0.950 0.331 82625 0.2250 0.123 0.2020
#> 6 0.749 0.578 160627 0.0948 0.000 0.1070
#> loudness speechiness tempo valence
#> 1 -1.828 0.0525 166.969 0.814
#> 2 -5.559 0.0868 174.003 0.816
#> 3 -13.879 0.0362 99.488 0.368
#> 4 -12.178 0.0395 171.758 0.227
#> 5 -21.150 0.0456 140.576 0.390
#> 6 -14.970 0.1430 87.479 0.358
Tahapan selanjutnya adalah menentukan jumlah cluster yang diinginkan
menggunakan metode elbow.
wss <- function(k) {
kmeans_result <- kmeans(data_cluster, centers = k)
return(sum(kmeans_result$withinss))
}
# Set the maximum number of clusters to test
max_k <- 10
# Calculate within-cluster sum of squares for each value of k
wss_values <- sapply(1:max_k, wss)
# Plot the elbow curve
plot(1:max_k, wss_values, type = "b", pch = 19, frame = FALSE, xlab = "Number of Clusters (k)", ylab = "Within-Cluster Sum of Squares", main = "Elbow Curve")
Dalam grafik elbow curve di atas, kita mencari elbow point, yaitu
titik di mana penurunan dalam within-cluster sum of squares
mulai merata atau melambat. Pada titik tersebut, kita dapat memilih
jumlah cluster yang optimal.
Dalam kasus ini, kita dapat memilih k = 7 sebagai jumlah cluster yang optimal.
RNGkind(sample.kind = "Rounding")
set.seed(100)
k <- 7
kmeans_result <- kmeans(data_cluster,centers = k) #kita mau coba buat 7 cluster
data_cluster$cluster_label <- as.factor(kmeans_result$cluster)
head(data_cluster)
#> acousticness danceability duration_ms energy instrumentalness liveness
#> 1 0.611 0.389 99373 0.9100 0.000 0.3460
#> 2 0.246 0.590 137373 0.7370 0.000 0.1510
#> 3 0.952 0.663 170267 0.1310 0.000 0.1030
#> 4 0.703 0.240 152427 0.3260 0.000 0.0985
#> 5 0.950 0.331 82625 0.2250 0.123 0.2020
#> 6 0.749 0.578 160627 0.0948 0.000 0.1070
#> loudness speechiness tempo valence cluster_label
#> 1 -1.828 0.0525 166.969 0.814 1
#> 2 -5.559 0.0868 174.003 0.816 1
#> 3 -13.879 0.0362 99.488 0.368 2
#> 4 -12.178 0.0395 171.758 0.227 1
#> 5 -21.150 0.0456 140.576 0.390 1
#> 6 -14.970 0.1430 87.479 0.358 2
library(tidyr)
cluster_profile <- data_cluster %>%
group_by(cluster_label) %>%
summarize(acousticness_mean = mean(acousticness),
danceability_mean = mean(danceability),
energy_mean = mean(energy),
instrumentalness_mean = mean(instrumentalness),
valence_mean = mean(valence))
sample(cluster_profile)
#> # A tibble: 7 × 6
#> danceability_mean valence_mean cluster_label acousticness_mean instr…¹ energ…²
#> <dbl> <dbl> <fct> <dbl> <dbl> <dbl>
#> 1 0.520 0.458 1 0.577 0.263 0.452
#> 2 0.588 0.498 2 0.314 0.0932 0.611
#> 3 0.339 0.227 3 0.739 0.463 0.327
#> 4 0.529 0.471 4 0.704 0.137 0.469
#> 5 0.403 0.275 5 0.590 0.386 0.418
#> 6 0.563 0.447 6 0.307 0.114 0.604
#> 7 0.491 0.362 7 0.414 0.240 0.523
#> # … with abbreviated variable names ¹instrumentalness_mean, ²energy_mean
Selama analisis k-means clustering, kita berhasil mengelompokkan lagu-lagu dalam 7 kluster berdasarkan fitur-fiturnya. Setiap kluster memiliki profil unik yang mencerminkan kombinasi tertentu dari fitur-fitur musik. Misalnya, kluster 1 cenderung memiliki tingkat akustik yang tinggi dan energi yang rendah, sementara kluster 2 memiliki tingkat akustik yang rendah dan energi yang tinggi.
Pertama, kita akan melakukan visualisasi menggunakan PCA untuk mereduksi dimensi data menjadi dua dimensi. Kita akan menggunakan biplot untuk menunjukkan hubungan antara variabel-variabel dalam data.
data_small <- data_pca %>% head(100)
pca_small <- prcomp(data_small, scale = T)
biplot(x = pca_small,
cex = 0.6,
scale = FALSE)
💡 Dari biplot diatas, terdapat outlier terluar, observasi 55 dan 15
ekstrim pada variable duration_ms
. dari panah merah, kita
tahu variabel mana yang paling banyak berkontribusi, untuk lebih
jelasnya dapat dilihat dalam urutan kontribusi berikut :
data_small[c(15,55),]
#> acousticness danceability duration_ms energy instrumentalness liveness
#> 15 0.970 0.400 159253 0.174 0.933 0.130
#> 55 0.924 0.683 101653 0.147 0.000 0.606
#> loudness speechiness tempo valence
#> 15 -13.869 0.0458 115.022 0.270
#> 55 -21.998 0.8220 32.244 0.595
Selanjutnya, kita dapat melihat kontribusi variabel terhadap setiap komponen utama (PC) dengan menggunakan grafik kontribusi:
library(factoextra)
fviz_contrib(X = pca_small,
choice = "var",
axes = 1)
Untuk visualisasi yang lebih menarik, kita dapat menggunakan fungsi fancy_biplot yang telah dibuat sebelumnya:
source("R/biplot.R")
fancy_biplot(pca_small)
Selanjutnya, kita akan melakukan visualisasi untuk hasil dari algoritma k-means clustering. Kita akan menggunakan grafik batang untuk menunjukkan profil masing-masing kluster berdasarkan nilai rata-rata dari fitur-fiturnya.
# Reshape the data frame for plotting
cluster_profile_melted <- cluster_profile %>%
gather(variable, value, -cluster_label)
ggplot(cluster_profile_melted, aes(x = cluster_label, y = value, fill = variable)) +
geom_bar(stat = "identity", position = "dodge") +
labs(x = "Cluster Label", y = "Mean Value", fill = "Variable") +
ggtitle("Cluster Profiles")
Selain itu, kita juga dapat menggunakan grafik radar interaktif untuk memvisualisasikan profil kluster:
library(ggiraphExtra)
ggRadar(data = cluster_profile,
aes(colours=cluster_label),
interactive = TRUE)
library(factoextra)
# Perform PCA on the scaled data
pca_result <- prcomp(data_scaled)
# Subset the cluster labels to match the number of data points in PCA
cluster_labels <- as.factor(kmeans_result$cluster)[1:nrow(pca_result$x)]
# Add cluster labels to PCA results
pca_result$cluster_label <- cluster_labels
# Create the combined plot
fviz_pca_biplot(pca_result, habillage = cluster_labels, addEllipses = TRUE, col.var = "navy")
library(corrplot)
# Analisis hubungan antara variabel dalam kluster
cluster_correlation <- data_cluster %>%
select(acousticness, danceability, energy, instrumentalness, valence, cluster_label)
# Korelasi antara variabel dalam kluster
cor_matrix <- cor(cluster_correlation[, -6])
print(cor_matrix)
#> acousticness danceability energy instrumentalness
#> acousticness 1.0000000 -0.3645456 -0.7255764 0.3161541
#> danceability -0.3645456 1.0000000 0.3258070 -0.3649412
#> energy -0.7255764 0.3258070 1.0000000 -0.3789569
#> instrumentalness 0.3161541 -0.3649412 -0.3789569 1.0000000
#> valence -0.3257982 0.5471540 0.4367712 -0.3075218
#> valence
#> acousticness -0.3257982
#> danceability 0.5471540
#> energy 0.4367712
#> instrumentalness -0.3075218
#> valence 1.0000000
# Visualisasi korelasi antara variabel dalam kluster
corrplot(cor_matrix, method = "color")
💡 Insight :
Acousticness dan Energy memiliki korelasi negatif yang kuat
(nilai -0.73), yang menunjukkan bahwa
lagu-lagu dengan tingkat akustik yang tinggi cenderung memiliki tingkat energi yang rendah
,
dan sebaliknya.
Danceability dan Valence memiliki korelasi positif yang moderat
(nilai 0.55), menunjukkan bahwa
lagu-lagu yang mudah untuk ditari cenderung memiliki tingkat keceriaan atau positivitas yang tinggi.
Acousticness dan Instrumentalness memiliki korelasi positif yang
moderat (nilai 0.32), yang menunjukkan bahwa
lagu-lagu dengan tingkat akustik yang tinggi juga cenderung memiliki tingkat unsur instrumental yang lebih tinggi.
Danceability dan Acousticness memiliki korelasi negatif yang
moderat (nilai -0.36), menunjukkan bahwa
lagu-lagu yang mudah untuk ditari cenderung memiliki tingkat akustik yang lebih rendah.
Energy dan Valence memiliki korelasi positif yang moderat (nilai
0.44), yang menunjukkan bahwa
lagu-lagu dengan tingkat energi yang tinggi juga cenderung memiliki tingkat keceriaan atau positivitas yang tinggi.
Dalam proyek ini, saya berhasil menganalisis data Spotify menggunakan teknik unsupervised learning. saya melakukan reduksi dimensi menggunakan PCA dan mengelompokkan lagu menggunakan algoritma k-means clustering. saya juga melakukan visualisasi data untuk memahami pola dan profil kluster.
Dalam visualisasi PCA, dapat dilihat hubungan antara variabel-variabel dalam data dan melihat kontribusi variabel terhadap komponen utama. Selain itu, visualisasi kluster memberikan gambaran tentang profil masing-masing kluster berdasarkan nilai rata-rata dari fitur-fiturnya.
Dengan menggunakan teknik unsupervised learning dan visualisasi, kita dapat memahami preferensi musik pengguna dan pola tersembunyi dalam data Spotify. Informasi ini dapat berguna untuk mengembangkan rekomendasi musik yang lebih personal dan memahami tren dalam industri musik.