Pada latihan kali ini kita akan melakukan analisis Principal Component Analysis (PCA) untuk meringkas data besar menjadi komponen-komponen signifikan dari data tersebut. Data yang digunakan adalah Spotify data tracks, yang mana data tersebut terdiri dari komponen-komponen musik pada spotify, seperti genre, artists, popularity, energy, loudness, dan lain-lain. Selain itu juga akan dianalisis menggunakan metode unsupervised machine learning lain untuk klasifikasi, yaitu K-Means. Tujuan dari latihan ini adalah melihat komponen yang signifikan dan outliers menggunakan metode PCA dan clustering menggunakan K-Means. Latihan ini menggunakan R studio dan library yang digunakan adalah sebagai berikut:
library(dplyr)
library(FactoMineR)
library(factoextra)
library(tidyr)
library(tidyverse)
Tahap pertama kita akan membaca data .csv dengan variabel bernama
spotify
spotify <- read.csv("SpotifyFEatures.csv", stringsAsFactors = T)
head(spotify)
Berikut adalah keterangan dari tiap kolom yang ada pada data
spotify
genre : The genre in which the track belongs
artist_name : The artists’ names who performed the track
track_name : Name of the track track_id: The
Spotify ID for the track popularity : The popularity of a
track is a value between 0 and 100, with 100 being the most popular
acousticness : A confidence measure from 0.0 to 1.0 of
whether the track is acoustic. 1.0 represents high confidence the track
is acoustic danceability : Danceability describes how
suitable a track is for dancing based on a combination of musical
elements including tempo, rhythm stability, beat strength, and overall
regularity. A value of 0.0 is least danceable and 1.0 is most danceable
duration_ms : The track length in milliseconds
energy : Energy is a measure from 0.0 to 1.0 and represents
a perceptual measure of intensity and activity. Typically, energetic
tracks feel fast, loud, and noisy. For example, death metal has high
energy, while a Bach prelude scores low on the scale
instrumentalness : Predicts whether a track contains no
vocals. “Ooh” and “aah” sounds are treated as instrumental in this
context. Rap or spoken word tracks are clearly “vocal”. The closer the
instrumentalness value is to 1.0, the greater likelihood the track
contains no vocal content key : The key the track is in
liveness : Detects the presence of an audience in the
recording. Higher liveness values represent an increased probability
that the track was performed live. A value above 0.8 provides strong
likelihood that the track is live loudness : The overall
loudness of a track in decibels (dB) mode : Mode indicates
the modality (major or minor) of a track, the type of scale from which
its melodic content is derived. speechiness : Speechiness
detects the presence of spoken words in a track. The more exclusively
speech-like the recording (e.g. talk show, audio book, poetry), the
closer to 1.0 the attribute value. Values above 0.66 describe tracks
that are probably made entirely of spoken words. Values between 0.33 and
0.66 describe tracks that may contain both music and speech, either in
sections or layered, including such cases as rap music. Values below
0.33 most likely represent music and other non-speech-like tracks
tempo : The overall estimated tempo of a track in beats per
minute (BPM). In musical terminology, tempo is the speed or pace of a
given piece and derives directly from the average beat duration
time_signature : An estimated time signature. The time
signature (meter) is a notational convention to specify how many beats
are in each bar (or measure). The time signature ranges from 3 to 7
indicating time signatures of 3/4, to 7/4 valence : A
measure from 0.0 to 1.0 describing the musical positiveness conveyed by
a track. Tracks with high valence sound more positive (e.g. happy,
cheerful, euphoric), while tracks with low valence sound more negative
(e.g. sad, depressed, angry)
anyNA(spotify)
#> [1] FALSE
Dikarenakan untuk metode unsupervised harus numerik, kolom yang akan dibuang adalah kolom - genre - artist_name - track_name - track_id - key - mode - time_signature
# your code
# meng-assign nilai dari kolom track_name menjadi rownames
rownames(spotify) <- spotify$name
# membuang kolom yang tidak digunakan
spotify_clean <- spotify %>%
select(-c(genre, artist_name, track_name, track_id, key, mode, time_signature))
spotify_clean %>% glimpse()
#> Rows: 232,725
#> Columns: 11
#> $ 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…
#> $ 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, -…
#> $ 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…
#> $ valence <dbl> 0.8140, 0.8160, 0.3680, 0.2270, 0.3900, 0.3580, 0.533…
#3. Exploratory Data Analysis
Kita akan mengecek nilai angka dari seluruh kolom data frame spotify untuk melihat range dari tiap variabel
summary(spotify)
#> genre artist_name track_name
#> Comedy : 9681 Giuseppe Verdi : 1394 Home : 100
#> Soundtrack: 9646 Giacomo Puccini : 1137 You : 71
#> Indie : 9543 Kimbo Children's Music : 971 Intro : 69
#> Jazz : 9441 Nobuo Uematsu : 825 Stay : 63
#> Pop : 9386 Richard Wagner : 804 Wake Up: 59
#> Electronic: 9377 Wolfgang Amadeus Mozart: 800 Closer : 58
#> (Other) :175651 (Other) :226794 (Other):232305
#> track_id popularity acousticness
#> 0UE0RhnRaEYsiYgXpyLoZc: 8 Min. : 0.00 Min. :0.0000
#> 0wY9rA9fJkuESyYm9uzVK5: 8 1st Qu.: 29.00 1st Qu.:0.0376
#> 3R73Y7X53MIQZWnKloWq5i: 8 Median : 43.00 Median :0.2320
#> 3uSSjnDMmoyERaAK9KvpJR: 8 Mean : 41.13 Mean :0.3686
#> 6AIte2Iej1QKlaofpjCzW1: 8 3rd Qu.: 55.00 3rd Qu.:0.7220
#> 6sVQNUvcVFTXvlk3ec0ngd: 8 Max. :100.00 Max. :0.9960
#> (Other) :232677
#> danceability duration_ms energy instrumentalness
#> Min. :0.0569 Min. : 15387 Min. :0.0000203 Min. :0.0000000
#> 1st Qu.:0.4350 1st Qu.: 182857 1st Qu.:0.3850000 1st Qu.:0.0000000
#> Median :0.5710 Median : 220427 Median :0.6050000 Median :0.0000443
#> Mean :0.5544 Mean : 235122 Mean :0.5709577 Mean :0.1483012
#> 3rd Qu.:0.6920 3rd Qu.: 265768 3rd Qu.:0.7870000 3rd Qu.:0.0358000
#> Max. :0.9890 Max. :5552917 Max. :0.9990000 Max. :0.9990000
#>
#> key liveness loudness mode
#> C :27583 Min. :0.00967 Min. :-52.457 Major:151744
#> G :26390 1st Qu.:0.09740 1st Qu.:-11.771 Minor: 80981
#> D :24077 Median :0.12800 Median : -7.762
#> C# :23201 Mean :0.21501 Mean : -9.570
#> A :22671 3rd Qu.:0.26400 3rd Qu.: -5.501
#> F :20279 Max. :1.00000 Max. : 3.744
#> (Other):88524
#> speechiness tempo time_signature valence
#> Min. :0.0222 Min. : 30.38 0/4: 8 Min. :0.0000
#> 1st Qu.:0.0367 1st Qu.: 92.96 1/4: 2608 1st Qu.:0.2370
#> Median :0.0501 Median :115.78 3/4: 24111 Median :0.4440
#> Mean :0.1208 Mean :117.67 4/4:200760 Mean :0.4549
#> 3rd Qu.:0.1050 3rd Qu.:139.05 5/4: 5238 3rd Qu.:0.6600
#> Max. :0.9670 Max. :242.90 Max. :1.0000
#>
Dari hasil di atas, masih terdapat nilai yang rangenya terlampau jauh. Terdapat nilai negatif, terdapat nilai desimal, bahkan terdapat nilai ratusan hingga ribuan. Karena angka-angka tersebut cukup signifikan untuk menentukan karakteristik dari data yang akan kita buat, maka kita perlu melakukan scaling pada data frame tersebut
Scaling menggunakan fungsi scaling
# your code here
spotify_scale <- scale(spotify_clean)
Data spotify setelah dilakukan scaling ada sebagai berikut
head(spotify_scale)
#> popularity acousticness danceability duration_ms energy
#> [1,] -2.261002 0.6833748 -0.8909329 -1.1413655 1.2869052
#> [2,] -2.206026 -0.3454664 0.1919933 -0.8218657 0.6302479
#> [3,] -2.096075 1.6445663 0.5852948 -0.5452965 -1.6699502
#> [4,] -2.261002 0.9426992 -1.6936990 -0.6952933 -0.9297874
#> [5,] -2.041100 1.6389288 -1.2034190 -1.2821808 -1.3131538
#> [6,] -2.261002 1.0723614 0.1273410 -0.6263486 -1.8073548
#> instrumentalness liveness loudness speechiness tempo valence
#> [1,] -0.48981747 0.66065975 1.2907007 -0.3679692 1.5956039 1.3807413
#> [2,] -0.48981747 -0.32283477 0.6686811 -0.1830817 1.8232495 1.3884316
#> [3,] -0.48981747 -0.56492573 -0.7184009 -0.4558311 -0.5883245 -0.3342114
#> [4,] -0.48981747 -0.58762176 -0.4348159 -0.4380431 1.7505932 -0.8763826
#> [5,] -0.08356631 -0.06561313 -1.9305971 -0.4051623 0.7414313 -0.2496173
#> [6,] -0.48981747 -0.54475148 -0.9002886 0.1198533 -0.9769791 -0.3726633
Kita akan membuat model PCA, yang mana adalah model yang idenya sama seperti menentukan model eigenvalue dan eigenvector, yang mana kita menentukan karakteristik data kita dalam berupa angka yang sebenarnya adalah pembuatan sumbu baru dari data yang telah kita miliki sebelumnya.
pca_spotify <- PCA(X = spotify_scale,
scale.unit = FALSE,
# quali.sup = qualivar, # index variabel kategorikal (qualivar)
graph = F,
ncp = 11) # memasukkan dengan jumlah dimensi data awal kita
Berikut adalah nilai eigen dari hasil pemodelan PCA menggunakan FactoMiner
# $eig ekuivalen -> `summary(prcomp())`
pca_spotify$eig
#> eigenvalue percentage of variance cumulative percentage of variance
#> comp 1 3.6104430 32.822350 32.82235
#> comp 2 1.7100248 15.545747 48.36810
#> comp 3 1.1712427 10.647707 59.01580
#> comp 4 0.9998305 9.089407 68.10521
#> comp 5 0.8617186 7.833839 75.93905
#> comp 6 0.7567533 6.879605 82.81866
#> comp 7 0.6378529 5.798688 88.61734
#> comp 8 0.4853764 4.412532 93.02988
#> comp 9 0.3751899 3.410832 96.44071
#> comp 10 0.2767438 2.515864 98.95657
#> comp 11 0.1147767 1.043429 100.00000
Eigenvector adalah vektor karakteristik dari tiap PC
# $var$coord ekuivalen -> `prcomp()$rotation`
pca_spotify$var$coord
#> Dim.1 Dim.2 Dim.3 Dim.4 Dim.5
#> popularity 0.44917466 -0.39028999 0.10760956 0.422083815 -0.4397128927
#> acousticness -0.79848319 0.24548236 -0.22570238 0.006878892 0.0262409864
#> danceability 0.63509619 0.07871289 -0.48777270 0.239667940 0.2205899208
#> duration_ms -0.11406387 -0.04283374 0.64233627 0.418290717 0.5984681336
#> energy 0.84799794 0.12674992 0.26729741 -0.097170181 0.0002286136
#> instrumentalness -0.61147458 -0.23915364 0.07559677 -0.132945278 0.1457079168
#> liveness 0.05634058 0.80987503 0.27460405 -0.056653595 -0.1159456730
#> loudness 0.88742087 -0.03224185 0.16603160 0.011411355 -0.0587820238
#> speechiness 0.05644629 0.84418745 0.03086711 0.068073171 -0.0886035122
#> tempo 0.29865883 -0.19533933 0.28027575 -0.733159532 0.0530787746
#> valence 0.61536734 0.09164875 -0.44559995 -0.128869764 0.4605008930
#> Dim.6 Dim.7 Dim.8 Dim.9 Dim.10
#> popularity 0.27909886 0.33729483 0.218855862 0.152032169 -0.008042847
#> acousticness 0.26175820 -0.03749408 0.107202305 0.160097978 0.368013093
#> danceability 0.19371407 0.23273855 -0.126586501 -0.358408124 0.078796508
#> duration_ms 0.19755256 -0.01300927 0.010087935 0.009425555 0.006027828
#> energy -0.30449316 0.03118583 -0.083559300 0.137511526 0.074861212
#> instrumentalness -0.38612700 0.60200934 -0.048901792 -0.007026588 0.093374835
#> liveness -0.09725448 0.10451736 0.421855399 -0.224176578 0.005442736
#> loudness -0.13496823 -0.11298891 -0.080988800 0.007920115 0.327619910
#> speechiness 0.18411893 0.23125097 -0.360378345 0.206644719 -0.084061096
#> tempo 0.47856910 0.14701952 -0.007557944 -0.053725723 0.011777191
#> valence -0.03707389 0.07856797 0.293318718 0.288156865 -0.078152551
#> Dim.11
#> popularity 0.0094461784
#> acousticness 0.0894468972
#> danceability 0.0636252634
#> duration_ms 0.0003046402
#> energy 0.2423947898
#> instrumentalness -0.0401377523
#> liveness -0.0153104453
#> loudness -0.1880124675
#> speechiness -0.0608448983
#> tempo 0.0045824622
#> valence -0.0544607858
Adalah hasil dari perkalian eigenvector
# $ind$coord ekuivalen -> `prcomp()$x`
as.data.frame(pca_spotify$ind$coord) %>% head()
Untuk memudahkan kita membayangkan hasil perhitungan eigenvalue dan eigenvector, kita akan membuat plot dari model pca yang telah kita buat
plot.PCA(
x = pca_spotify,
choix = "ind",
# habillage = "not_paid",
select = "contrib 10",
invisible = "quali"
)
Dari plot di atas, kita mengetahui bahwa PC1 dan PC2 cukup menggambarkan karakteristik data secara keseluruhan. Meskipun dari plot tampak bahwa data terlalu banyak, amun bisa disimpulkan bahwa terdapat karakteristik yang lebih banyak di bawah sumbu x, dan juga terdapat beberapa outliers dari karakter yang mayoritas sejenis. Hal ini belum bisa menyimpulkan apa-apa, sehingga kita akan dibantu oleh bentuk plot lainnya
Variable Factor Map
Kita akan melihat korelasi antar variabel dari tiap PC.
plot.PCA(x = pca_spotify, # objek PCA factominer
choix = "var") # var: variable factor map -> ind: individual factor map
Dari plot di atas, PC1 paling banyak merangkum energy, danceability, dan loudness, instrumentalness, dan acousticness. Sedangkan PC2 paling banyak merangkum spechiness, liveness, dan popularity. Pasangan variabel yang saling berkorelasi tinggi positif adalah speechiness dan liveness, dan danceability dan loudness.
Dimension Description
Selanjutnya kita akan menggunakan fungsi fviz_contrib
untuk melihat urutan kontribusi variabel ke tiap PC
fviz_contrib(X = pca_spotify,
choice = "var",
axes = 2) # PC1 = 1, PC2 = 2.
Berdasarkan plot di atas, dapat disimpulkan bahwa variabel yang melebihi garis putus-putus merah, variabel tersebut dirangkum paling banyak pada PC 1 dan PC 2. Pada kasus ini, speechiness dan liveness adalah variabel yang paling banyak dirangkum.
Untuk mengurangi jumlah dimensi pada PCA, pertama-tama kita akan mengecek ulang nilai eigenvalue dari model pca.
# PCA summary -> summary(prcomp())
pca_spotify$eig
#> eigenvalue percentage of variance cumulative percentage of variance
#> comp 1 3.6104430 32.822350 32.82235
#> comp 2 1.7100248 15.545747 48.36810
#> comp 3 1.1712427 10.647707 59.01580
#> comp 4 0.9998305 9.089407 68.10521
#> comp 5 0.8617186 7.833839 75.93905
#> comp 6 0.7567533 6.879605 82.81866
#> comp 7 0.6378529 5.798688 88.61734
#> comp 8 0.4853764 4.412532 93.02988
#> comp 9 0.3751899 3.410832 96.44071
#> comp 10 0.2767438 2.515864 98.95657
#> comp 11 0.1147767 1.043429 100.00000
Apabila kita ingin mengambil minimal 80% informasi, maka kita membutuhkan 6 PC
Maka kita akan mengambil 6 PC pertama
pca_spotify$ind$coord %>% head()
#> Dim.1 Dim.2 Dim.3 Dim.4 Dim.5 Dim.6
#> 1 0.9904481 0.9993903 -0.1597105 -3.0962912 0.71325308 -0.74345195
#> 2 1.2096105 0.2730414 -0.6842276 -2.7298245 1.28269932 -0.12134335
#> 3 -2.1123978 0.3531611 -1.8668172 -0.2666744 0.70972338 0.39952609
#> 4 -1.9545010 -0.1868432 0.2513141 -2.6613814 -0.02211554 0.60691571
#> 5 -2.9355815 0.3915754 -1.1231315 -2.0937683 -0.02518811 0.41551544
#> 6 -2.2612410 0.7007202 -1.7307093 -0.1446502 0.52331036 0.03778243
#> Dim.7 Dim.8 Dim.9 Dim.10 Dim.11
#> 1 -1.3200974 0.4246202 0.576058781 1.16234095 0.04739096
#> 2 -0.9083572 -0.4478824 -0.057434104 0.09104371 -0.13059333
#> 3 -1.4628733 -0.4420655 -0.872496223 0.59542626 -0.09975048
#> 4 -1.7930776 -0.5882799 -0.041750169 0.17564117 -0.22897820
#> 5 -1.1238702 0.2555989 -0.007753993 -0.30349575 0.41629524
#> 6 -1.5234275 -0.7598055 -0.626642226 -0.09946476 -0.44224934
spot_keep <- as.data.frame(pca_spotify$ind$coord[,1:6])
spot_keep %>% head()
Selanjutnya kita akan mencoba membuat Biplot. Biplot berguna untuk kita menganalisa adanya korelasi, dan juga outliers
# subset 100 data pertama agar tidak terlalu menumpuk
spot_small <- spotify_clean %>% head(100)
# melakukan PCA
pca_small <- prcomp(spot_small, scale = TRUE)
# membuat biplot
biplot(x = pca_small,
cex = 0.7,
scale = FALSE)
Dari plot di atas, outliers yang sangat terlihat adalah data nomor 55
spotify_clean[55,]
Ternyata data nomor 55 memiliki popularity nol, yang mana membuat dia jauh dari panah yang lain
Selain data no 55, kita bisa lebih jelas melihat terdapat outliers pada data no 16 dan no 97
spotify_clean[16,]
spotify_clean[97,]
Yang menyebabkan dua data di atas termasuk outliers adalah selain karena popularitynya nol, melainkan juga dikarenakan nilai spechiness yang terlampau sangat tinggi dibandingkan data sekitarnya.
K-Means Clusteringa adalah clustering dengan menyamakan jenis karakteristik berdasarkan kemiripan data yang ditranslate dalam bentuk jarak. Maka dari itu untuk pemodelan ini dibutuhkan data numerik.
Dengan clustering kita dapat membuat kelompok musik yang memiliki karakteristik genre yang sama pada tiap clusternya
Selanjutnya kita akan mengulangi proses persiapan data, dikarenakan
kita memerlukan index yang baru yaitu kolom track_name
untuk membantu mengklasifikasikan kelompok musik yang kita inginkan.
#menghilangkan nama lagu yang sama sehingga menjadi unique
spotify <- spotify[!duplicated(spotify$track_name), ]
#set kolom track_name sebagai rownames
rownames(spotify) <- spotify$track_name
#remove original track_name column from data frame
spotify$track_name <- NULL
#view updated data frame
head(spotify)
Selanjutnya kita proses ulang data spotify dengan index baru, sama
seperti pre-processing data untuk PCA, bedanya kita tidak perlu
menuliskan kolom track_name saat menghilangkan kolom yang
tidak akan kita gunakan
# membuang kolom yang tidak digunakan
spotify_clean <- spotify %>%
select(-c(genre, artist_name, track_id, key, mode, time_signature))
Kemudian kita scale ulang data spotify
spotify_scale <- scale(spotify_clean)
Berikut adalah data spotify setelah dilakukan scaling
head(spotify_scale)
#> popularity acousticness danceability
#> C'est beau de faire un Show -2.049284 0.5280107 -0.7598805
#> Perdu d'avance (par Gad Elmaleh) -1.991859 -0.4557947 0.2819632
#> Don't Let Me Be Lonely Tonight -1.877008 1.4471276 0.6603442
#> Dis-moi Monsieur Gordon Cooper -2.049284 0.7759836 -1.5321925
#> Ouverture -1.819583 1.4417368 -1.0605120
#> Le petit souper aux chandelles -2.049284 0.8999700 0.2197635
#> duration_ms energy instrumentalness
#> C'est beau de faire un Show -1.0129040 1.2731734 -0.5505784
#> Perdu d'avance (par Gad Elmaleh) -0.7352963 0.6573688 -0.5505784
#> Don't Let Me Be Lonely Tonight -0.4949902 -1.4997272 -0.5505784
#> Dis-moi Monsieur Gordon Cooper -0.6253198 -0.8056122 -0.5505784
#> Ouverture -1.1352560 -1.1651282 -0.1781535
#> Le petit souper aux chandelles -0.5654149 -1.6285834 -0.5505784
#> liveness loudness speechiness tempo
#> C'est beau de faire un Show 0.5443334 1.2923966 -0.37223500 1.5947595
#> Perdu d'avance (par Gad Elmaleh) -0.3614760 0.7286643 -0.20858210 1.8189239
#> Don't Let Me Be Lonely Tonight -0.5844445 -0.5284391 -0.45000591 -0.5557715
#> Dis-moi Monsieur Gordon Cooper -0.6053478 -0.2714279 -0.43426088 1.7473787
#> Ouverture -0.1245720 -1.6270447 -0.40515643 0.7536492
#> Le petit souper aux chandelles -0.5658638 -0.6932828 0.05956055 -0.9384826
#> valence
#> C'est beau de faire un Show 1.3543538
#> Perdu d'avance (par Gad Elmaleh) 1.3617662
#> Don't Let Me Be Lonely Tonight -0.2986175
#> Dis-moi Monsieur Gordon Cooper -0.8211936
#> Ouverture -0.2170808
#> Le petit souper aux chandelles -0.3356796
Membuat cluster menggunakan fungsi kmeans. Kita akan
menggunakan 5 centers sebagai acuan kita dalam pembentukan cluster.
Memilih 5 centers dengan pertimbangan banyaknya track yang
dianalisis.
RNGkind(sample.kind = "Rounding")
set.seed(100)
spotify_cluster <- kmeans(x = spotify_scale,
centers = 5)
Selanjutnya kita akan mengecek banyaknya data pada tiap cluster
spotify_cluster$size
#> [1] 26320 52693 21679 39014 8909
spotify_cluster$centers
#> popularity acousticness danceability duration_ms energy instrumentalness
#> 1 -0.5240686 1.0008838 -0.2892148 -0.15984313 -0.9489471 -0.2876111
#> 2 0.4854918 -0.5522806 0.8273668 -0.09261711 0.4094024 -0.3477326
#> 3 -0.4446846 1.1683417 -1.3240279 0.24579113 -1.3999888 1.7608657
#> 4 0.1439168 -0.8132621 -0.2201466 0.08160808 0.7749498 -0.1896271
#> 5 -0.8713644 1.0279705 0.1468290 0.06453936 0.3951186 -0.5480635
#> liveness loudness speechiness tempo valence
#> 1 -0.1502987 -0.4891925 -0.3107940 -0.1685249 -0.343655524
#> 2 -0.2589489 0.4879831 -0.1438535 -0.2523826 0.656898563
#> 3 -0.3983677 -1.6483999 -0.4081409 -0.4891775 -1.127646374
#> 4 0.1405609 0.6435782 -0.1892740 0.8652927 -0.001440749
#> 5 2.3294451 -0.2481362 3.5910418 -0.6082932 -0.119708997
Kita akan melihat hasil clustering dari setiap observasi
head(spotify_cluster$cluster)
#> C'est beau de faire un Show Perdu d'avance (par Gad Elmaleh)
#> 4 4
#> Don't Let Me Be Lonely Tonight Dis-moi Monsieur Gordon Cooper
#> 1 1
#> Ouverture Le petit souper aux chandelles
#> 1 1
Kita akan melihat jumlah iterasi algoritma k-means sampai dihasilkan cluster yang stabil
spotify_cluster$iter
#> [1] 6
Hasil iterasi yang dibutuhkan untuk mencapai cluster yang stabil adalah 6 kali.
Kita akan menentukan hasil clustering yang kita tentukan apakah baik atau tidak, ditentukan dari tig anilai berikut:
Within Sum of Squares ($withinss) jumlah jarak
kuadrat dari tiap data ke centroid tiap cluster
Between Sum of Squares ($betweenss): jumlah jarak
kuadrat dari tiap centroid ke rata-rata global.
Total Sum of Squares ($totss): jumlah jarak kuadrat
dari tiap observasi ke rata-rata global.
Cek nilai wss
spotify_cluster$withinss
#> [1] 165036.36 232618.54 160962.65 227131.46 79456.46
Cek nilai bss dan tss
spotify_cluster$betweenss
#> [1] 769548.5
spotify_cluster$totss
#> [1] 1634754
Cek rasio bss/tss
spotify_cluster$betweenss / spotify_cluster$totss
#> [1] 0.4707427
Clustering yang baik adalah yang memiliki nilai wss yang rendah, dikarenakan jarak antar data di dalam cluster semakin kecil, yang mana menunjukkan adanya karakteristik cluster yang kuat. Namun nilai wss yang ditemukan memiliki range 79.000 - 227.000, yang mana cukup jauh.
Kemudian nilai bss/tss juga menentukan baik atau
tidaknya clustering. Clustering yang baik adalah yang memiliki nilai
bss/tss mendekati 1. Sementara nilai bss/tss
yang kita miliki sebesar 0.47, yang mana masih jauh dari angka 1.
Selanjutnya akan kita buat lagi jumlah cluster yang lebih besar, kali
ini berdasarkan jumlah genre pada data di spotify.
unique(spotify$genre)
#> [1] Movie R&B A Capella Alternative
#> [5] Country Dance Electronic Anime
#> [9] Folk Blues Opera Hip-Hop
#> [13] Children's Music Children’s Music Rap Indie
#> [17] Classical Pop Reggae Reggaeton
#> [21] Jazz Rock Ska Comedy
#> [25] Soul Soundtrack World
#> 27 Levels: A Capella Alternative Anime Blues ... World
RNGkind(sample.kind = "Rounding")
set.seed(100)
spotify_cluster27 <- kmeans(x = spotify_scale,
centers = 27)
Cek rasio wss
spotify_cluster27$withinss
#> [1] 13844.072 19599.227 19572.562 10043.623 27943.862 20159.921 14350.700
#> [8] 16953.158 33351.575 18829.397 20165.779 30506.812 9984.040 12662.742
#> [15] 23397.159 17668.778 22942.454 13862.741 21697.649 19130.523 14628.544
#> [22] 13975.522 4658.234 14617.270 11110.254 14615.444 21514.630
Cek rasio bss/tss
spotify_cluster27$betweenss / spotify_cluster$totss
#> [1] 0.7052849
Cek jumlah data dalam setiap cluster
spotify_cluster27$size
#> [1] 3750 8395 2117 2455 5736 9371 5302 7482 7452 7843 7886 8703
#> [13] 2718 3820 5737 6414 5093 5149 10064 7757 5065 5425 103 2872
#> [25] 2153 4874 4879
Dengan memilih nilai cluster yang lebih besar, yaitu 27 cluster,
menunjukkan nilai wss yang lebih rendah, dengan range 9.000
- 33.000, dengan nilai bss/tss mencapai nilai 0.7. Hal ini
menjadi parameter yang lebih baik dari yang sebelumnya, dan selanjutnya
kita akan menggunakan 27 cluster ini.
Membuat kolom baru yang berisikan informasi label dari cluster yang
terbentuk menggunakan k = 27. Kita akan memasukkan label cluster ke data
awal spotify_clean dengan nama kolom kelompok.
spotify_clean$cluster <- as.factor(spotify_cluster27$cluster)
spotify_clean %>% head()
Selanjutnya kita akan melakukan grouping berdasarkan cluster yang terbentuk, untuk mengetahui karakteristik dari masing-masing cluster
# melakukan profiling
spotify_centroid <- spotify_clean %>%
group_by(cluster) %>%
summarise_all(mean)
spotify_centroid
Untuk mempermudah profiling, kita akanmembuat tabel yang menampilkan cluster dengan nilai terendah dan tertinggi untuk masing-masing karakteristik lagu
spotify_centroid %>%
pivot_longer(-cluster) %>%
group_by(name) %>%
summarize(
kelompok_min = which.min(value),
kelompok_max = which.max(value))
Berikut adalah contoh beberapa sample analisis profiling tiap cluster dan perkiraan label pade masing-masing cluster
Cluster 15 : - Paling tinggi liveness dan speechiness - Label : Musik live
Cluster 12 : - Paling rendah di: danceability, energy, liveness, loudness, speechiness, tempo, dan valence - Label : Musik Lo-fi
Kita akan membuat visualisasi clustering. Karena untuk kebutuhan visualisasi, kita akan membuat model kmeans baru dengan 100 data pertama saja dengan 5 cluster
spot_small_cluster <- spotify_clean %>% select(-cluster) %>% head(100)
spotify_cluster_small <- kmeans(x = spotify_scale %>% head(100),
centers = 5)
# visualisasi 2 dimensi
fviz_cluster(object = spotify_cluster_small,
data = spot_small_cluster )
Berdasarkan visualisasi di atas, dapat dilihat bahwa terdapat beberapa cluster yang menumpuk, sehingga sulit terbaca. Sedikit hal yang bisa disimpulkan adalah terdapat kesamaan judul lagu berbahasa Perancis yang membuat beberapa lagu tersebut terdapat di cluster yang sama.
KIta akan membuat visualisasi yang menampilkan tampilan individual
dan variables factor map menjadi satu menggunakan fungsi
fviz_pca_biplot() . Untuk kemudahan pembuatan visualisasi,
kita akan membuat model PCA lagi dengan 100 data pertama dari data
spotify yang sudah dilakukan scaling.
# buat model PCA
spot_pca <- PCA(X = spotify_scale %>% head(100),
scale.unit = F,
graph = F)
Selanjutnya kita akan membuat visualisasi dari fungsi PCA yang telah
dibuat dari 100 data pertama (spot_pca)
fviz_pca_biplot(X = spot_pca,
geom.ind = "point",
addEllipses = T)
Dari plot di atas, kita dapat melihat bahwa dari seluruh variabel dalam 100 data pertama, mayoritas dipengaruhi oleh variabel-variabel seperti energy, valence, danceablity, loudness, instrumentalness, dan acousticness, dan lain-lain sesuai plot, kecuali duration_ms. Dari plot ini, dapat disimpulkan bahwa variabel-variable ini membentuk 1 cluster, dan tidak tampak cluster yang lain yang terbentuk.
Berdasarkan latihan kali ini menggunakan model spotify, terdapat beberapa evaluasi. Evaluasi yang pertama, alangkah baiknya apabila unsupervised learning menggunakan data yang tidak terlalu banyak, namun cukup. Karena dengan data yang berlebih, tidak mudah untuk divisualisasikan. Meskipun begitu, bukan menjadi hal yang tidak mungkin untuk dianalisis. Berdasarkan model PCA dan K-means, hal yang dapat dibandingkan adalah variabel-variabel yang mempengaruhi terbentuknya suatu cluster. Sebagai contoh, dari hasil visualisasi PCA, terdapat korelasi yang sangat kuat antara speechiness - liveness dan danceability - loudness. Sementara dari hasil clustering, sebagai contoh cluster 15 memiliki speechiness - liveness tertinggi. Hal ini menunjukkan kedua model ini bekerja dengan baik menentukan klasifikasi menggunakan metode eigenvalue - eigenvector maupun berdasarkan jarak kuadrat dengan penentuan jumlah cluster pada K-means.