Dalam era digital saat ini, industri musik mengalami perubahan yang signifikan. Platform streaming seperti Spotify telah merevolusi cara kita mendengarkan dan menemukan musik. Jutaan lagu dari berbagai genre dan artis tersedia dengan mudah, menghadirkan tantangan baru dalam mengelompokkan dan memahami preferensi musik pengguna.
Klasterisasi musik adalah salah satu metode yang digunakan untuk menganalisis dan mengelompokkan lagu berdasarkan karakteristik musiknya. Salah satu pendekatan yang umum digunakan adalah penggunaan metode KMeans dan teknik reduksi dimensi PCA (Principal Component Analysis).
Metode KMeans adalah algoritma klasterisasi yang populer dalam dunia data mining dan pembelajaran mesin. Metode ini mengelompokkan data ke dalam kelompok-kelompok yang memiliki kemiripan tertentu berdasarkan fitur-fitur yang diberikan. Dalam konteks klasterisasi musik Spotify, fitur-fitur ini dapat meliputi tempo, energi, danceability, valence, dan banyak lagi. Dengan menggunakan metode KMeans, kita dapat mengidentifikasi kelompok-kelompok musik yang memiliki karakteristik yang serupa.
Langkah pertama dalam analisis klasterisasi musik Spotify adalah menerapkan metode KMeans. Kita akan menggunakan fitur-fitur musik yang disediakan oleh Spotify API untuk menggambarkan setiap lagu. Fitur-fitur ini dapat mencakup informasi seperti tempo, durasi, instrumen, dan banyak lagi. Dengan menggunakan metode KMeans, kita dapat mengelompokkan lagu-lagu berdasarkan karakteristik musik mereka. Kelompok-kelompok ini akan membantu kita mengidentifikasi kesamaan dalam preferensi musik dan mengungkapkan pola-pola yang mungkin tersembunyi dalam data musik Spotify.
Setelah melakukan klasterisasi dengan KMeans, langkah selanjutnya adalah menerapkan PCA. PCA akan membantu mengurangi dimensi data musik ke beberapa komponen utama yang paling signifikan. Reduksi dimensi ini berguna untuk menghilangkan kelebihan variabel dan memperoleh representasi yang lebih sederhana namun informatif dari data musik. Dengan menggunakan PCA, kita dapat memvisualisasikan data musik dalam ruang yang lebih rendah dimensi dan mengidentifikasi fitur-fitur yang paling berkontribusi terhadap variasi dalam dataset.
Dengan memahami dan mengelompokkan musik berdasarkan karakteristiknya menggunakan metode KMeans, kemudian mengurangi dimensi data menggunakan PCA, kita dapat membantu pengguna Spotify menemukan lagu-lagu baru yang sesuai dengan preferensi mereka. Analisis klasterisasi musik Spotify dengan metode KMeans dan PCA tidak hanya memberikan wawasan tentang preferensi musik individu, tetapi juga dapat digunakan untuk mengidentifikasi tren dan pola dalam musik secara keseluruhan.
Dalam penelitian ini, kami akan menerapkan metode KMeans dan PCA pada data musik Spotify untuk mengungkapkan struktur dan kelompok musik yang ada. Melalui kombinasi kedua metode ini, kita akan memperoleh pemahaman yang lebih baik tentang preferensi musik pengguna dan karakteristik musik yang saling terkait.
#Data Preparation
# Import library
library(tidyverse)
library(FactoMineR)
library(factoextra)
library(plotly)
df_spotify <- read_csv("SpotifyFeatures.csv")
head(df_spotify)
## # A tibble: 6 × 18
## genre artist_name track_name track_id popularity acousticness danceability
## <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl>
## 1 Movie Henri Salvador C'est bea… 0BRjO6g… 0 0.611 0.389
## 2 Movie Martin & les f… Perdu d'a… 0BjC1Nf… 1 0.246 0.59
## 3 Movie Joseph Williams Don't Let… 0CoSDzo… 3 0.952 0.663
## 4 Movie Henri Salvador Dis-moi M… 0Gc6TVm… 0 0.703 0.24
## 5 Movie Fabien Nataf Ouverture 0IuslXp… 4 0.95 0.331
## 6 Movie Henri Salvador Le petit … 0Mf1jKa… 0 0.749 0.578
## # ℹ 11 more variables: duration_ms <dbl>, energy <dbl>, instrumentalness <dbl>,
## # key <chr>, liveness <dbl>, loudness <dbl>, mode <chr>, speechiness <dbl>,
## # tempo <dbl>, time_signature <chr>, valence <dbl>
glimpse(df_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 <dbl> 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 <dbl> 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(df_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
anyNA(df_spotify)
## [1] FALSE
# songs per genre
df_spotify %>% group_by(Genre = genre) %>%
summarise(No_of_tracks = n()) %>% knitr::kable()
| Genre | No_of_tracks |
|---|---|
| A Capella | 119 |
| Alternative | 9263 |
| Anime | 8936 |
| Blues | 9023 |
| Children’s Music | 5403 |
| Children’s Music | 9353 |
| Classical | 9256 |
| Comedy | 9681 |
| Country | 8664 |
| Dance | 8701 |
| Electronic | 9377 |
| Folk | 9299 |
| Hip-Hop | 9295 |
| Indie | 9543 |
| Jazz | 9441 |
| Movie | 7806 |
| Opera | 8280 |
| Pop | 9386 |
| R&B | 8992 |
| Rap | 9232 |
| Reggae | 8771 |
| Reggaeton | 8927 |
| Rock | 9272 |
| Ska | 8874 |
| Soul | 9089 |
| Soundtrack | 9646 |
| World | 9096 |
spotify_top80 <-
df_spotify %>%
filter(popularity >= 80)
spotify_top80
## # A tibble: 1,239 × 18
## genre artist_name track_name track_id popularity acousticness danceability
## <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl>
## 1 Alterna… Joji Sanctuary 3xaugmC… 83 0.422 0.552
## 2 Alterna… Joji SLOW DANC… 0rKtyWc… 81 0.544 0.515
## 3 Alterna… Linkin Park In the End 60a0Rd6… 80 0.0103 0.542
## 4 Dance Ariana Gra… break up … 4kV4N9D… 99 0.0421 0.726
## 5 Dance Ariana Gra… 7 rings 14msK75… 100 0.578 0.725
## 6 Dance Halsey Without Me 5p7ujcr… 97 0.297 0.752
## 7 Dance Ariana Gra… needy 1TEL6Ml… 92 0.78 0.647
## 8 Dance Ariana Gra… NASA 4uTvPEr… 91 0.451 0.747
## 9 Dance Ariana Gra… thank u, … 2rPE9A1… 95 0.28 0.724
## 10 Dance Ariana Gra… bloodline 2hloaUo… 91 0.0815 0.758
## # ℹ 1,229 more rows
## # ℹ 11 more variables: duration_ms <dbl>, energy <dbl>, instrumentalness <dbl>,
## # key <chr>, liveness <dbl>, loudness <dbl>, mode <chr>, speechiness <dbl>,
## # tempo <dbl>, time_signature <chr>, valence <dbl>
Terdapat 1239 track musik yang memiliki popularitas diatas 80. mari kita lihat jenis genre apa saja yang populer
popular_genre <-
spotify_top80 %>%
group_by(genre) %>%
summarise(count = n()) %>%
arrange(desc(count))
popular_genre
## # A tibble: 16 × 2
## genre count
## <chr> <int>
## 1 Pop 462
## 2 Rap 209
## 3 Dance 167
## 4 Hip-Hop 146
## 5 Rock 64
## 6 Reggaeton 61
## 7 R&B 58
## 8 Indie 28
## 9 Children’s Music 21
## 10 Folk 7
## 11 Soul 5
## 12 Alternative 3
## 13 Country 3
## 14 Electronic 3
## 15 Blues 1
## 16 Movie 1
plot_ly(popular_genre, x = ~reorder(genre, -count), y = ~count, type = "bar",
marker = list(color = "steelblue")) %>%
layout(title = "Jumlah Lagu Populer Berdasarkan Genre",
xaxis = list(title = "Genre"),
yaxis = list(title = "Jumlah Lagu"))
observation <-
spotify_top80 %>%
filter(genre %in% c("Pop", "Rap", "Dance"))
observation
## # A tibble: 838 × 18
## genre artist_name track_name track_id popularity acousticness danceability
## <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl>
## 1 Dance Ariana Grande break up w… 4kV4N9D… 99 0.0421 0.726
## 2 Dance Ariana Grande 7 rings 14msK75… 100 0.578 0.725
## 3 Dance Halsey Without Me 5p7ujcr… 97 0.297 0.752
## 4 Dance Ariana Grande needy 1TEL6Ml… 92 0.78 0.647
## 5 Dance Ariana Grande NASA 4uTvPEr… 91 0.451 0.747
## 6 Dance Ariana Grande thank u, n… 2rPE9A1… 95 0.28 0.724
## 7 Dance Ariana Grande bloodline 2hloaUo… 91 0.0815 0.758
## 8 Dance Ariana Grande bad idea 5Il6Oe7… 91 0.0268 0.847
## 9 Dance benny blanco Eastside (… 0d2iYfp… 91 0.555 0.56
## 10 Dance Ariana Grande fake smile 3wFLWP0… 90 0.329 0.45
## # ℹ 828 more rows
## # ℹ 11 more variables: duration_ms <dbl>, energy <dbl>, instrumentalness <dbl>,
## # key <chr>, liveness <dbl>, loudness <dbl>, mode <chr>, speechiness <dbl>,
## # tempo <dbl>, time_signature <chr>, valence <dbl>
Our data has 838 rows and 18 column, we want to reduce the dimension without losing information contain in data. We can make Principal Component Analysis to reduce data dimension without losing information. We want to keep 85% of information from our data.
spotify <- df_spotify %>% select(-c(1,4,8,11,14,17)) %>% filter(popularity > 80) %>% mutate(track_name = as.factor(track_name))
glimpse(spotify)
## Rows: 989
## Columns: 12
## $ artist_name <chr> "Joji", "Joji", "Ariana Grande", "Ariana Grande", "Ha…
## $ track_name <fct> "Sanctuary", "SLOW DANCING IN THE DARK", "break up wi…
## $ popularity <dbl> 83, 81, 99, 100, 97, 92, 91, 95, 91, 91, 91, 90, 93, …
## $ acousticness <dbl> 0.42200, 0.54400, 0.04210, 0.57800, 0.29700, 0.78000,…
## $ danceability <dbl> 0.552, 0.515, 0.726, 0.725, 0.752, 0.647, 0.747, 0.72…
## $ energy <dbl> 0.650, 0.479, 0.554, 0.321, 0.488, 0.309, 0.458, 0.64…
## $ instrumentalness <dbl> 2.75e-04, 5.98e-03, 0.00e+00, 0.00e+00, 9.11e-06, 7.4…
## $ liveness <dbl> 0.3720, 0.1910, 0.1060, 0.0884, 0.0936, 0.2020, 0.252…
## $ loudness <dbl> -7.199, -7.458, -5.290, -10.744, -7.050, -7.948, -6.8…
## $ speechiness <dbl> 0.1280, 0.0261, 0.0917, 0.3230, 0.0705, 0.0366, 0.303…
## $ tempo <dbl> 167.788, 88.964, 169.999, 70.142, 136.041, 87.045, 75…
## $ valence <dbl> 0.316, 0.284, 0.335, 0.319, 0.533, 0.195, 0.470, 0.43…
spotify_scaled <- scale(spotify[,-c(1,2)])
hist(spotify_scaled)
wss <- function(data, maxCluster = 9) {
# Initialize within sum of squares
SSw <- (nrow(data) - 1) * sum(apply(data, 2, var))
SSw <- vector()
set.seed(100)
for (i in 2:maxCluster) {
SSw[i] <- sum(kmeans(data, centers = i)$withinss)
}
plot(1:maxCluster, SSw, type = "o", xlab = "Number of Clusters", ylab = "Within groups sum of squares", pch=19)
}
wss(spotify_scaled)
set.seed(1000)
spotify_km <- kmeans(spotify_scaled, centers = 7)
spotify_km$size
## [1] 118 111 165 241 135 14 205
spotify_km$centers
## popularity acousticness danceability energy instrumentalness liveness
## 1 1.94159213 0.1507840 0.4788512 -0.1470717 -0.03024675 -0.2058154
## 2 -0.01808653 -0.4666430 0.2256204 0.3575940 -0.04632162 2.0952297
## 3 -0.33474773 -0.5176881 0.7558293 -0.3485679 -0.14598928 -0.1901233
## 4 -0.36047053 -0.1453734 0.1720450 0.7769837 -0.13655910 -0.4142955
## 5 -0.19282994 1.7561217 -0.4712820 -1.2606631 -0.04465374 -0.2498212
## 6 -0.51655074 0.5111424 -0.3988484 0.1176130 7.02789630 -0.4619475
## 7 -0.25234020 -0.4379221 -0.8708099 0.0803176 -0.13001220 -0.1798808
## loudness speechiness tempo valence
## 1 0.17306110 -0.02168820 -0.4642504 -0.06908389
## 2 0.28865453 -0.09310844 -0.0092440 0.16564508
## 3 -0.29179676 1.45612037 0.4470577 -0.02481384
## 4 0.64745198 -0.37822414 -0.2785129 0.91577121
## 5 -1.24573210 -0.27161454 -0.1560615 -0.55877648
## 6 -0.65029565 -0.49504939 0.3075627 -0.15018209
## 7 0.08256902 -0.45178021 0.3215959 -0.72831175
fviz_cluster(spotify_km, data=spotify_scaled)
spotify_pca <- PCA(spotify_scaled,
graph = F,
ncp = 5)
plot.PCA(spotify_pca,
choix = c("ind"),
habillage = 1,
select = "contrib7",
invisible = "quali",)
plot.PCA(spotify_pca, choix = c("var"))
# include the cluster column into Spotify data
spotify$cluster <- spotify_km$cluster
# subset data to variables we need
spoti_cluster <- spotify %>% group_by(cluster) %>% select(popularity, danceability, speechiness) %>% summarise_all("mean")
## Adding missing grouping variables: `cluster`
spoti_cluster
## # A tibble: 7 × 4
## cluster popularity danceability speechiness
## <int> <dbl> <dbl> <dbl>
## 1 1 92.5 0.761 0.122
## 2 2 84.8 0.729 0.114
## 3 3 83.6 0.796 0.280
## 4 4 83.5 0.722 0.0833
## 5 5 84.1 0.641 0.0947
## 6 6 82.9 0.650 0.0707
## 7 7 83.9 0.590 0.0754
spotify %>% filter(cluster == "5") %>% arrange(desc(popularity))
## # A tibble: 135 × 13
## artist_name track_name popularity acousticness danceability energy
## <chr> <fct> <dbl> <dbl> <dbl> <dbl>
## 1 Ariana Grande needy 92 0.78 0.647 0.309
## 2 Alec Benjamin Let Me Down Slowly 92 0.74 0.652 0.557
## 3 Ariana Grande needy 92 0.78 0.647 0.309
## 4 Alec Benjamin Let Me Down Slowly 92 0.74 0.652 0.557
## 5 Dean Lewis Be Alright 92 0.697 0.553 0.586
## 6 Lewis Capaldi Someone You Loved 91 0.751 0.501 0.405
## 7 Lady Gaga Shallow - Radio Ed… 90 0.416 0.575 0.33
## 8 XXXTENTACION Jocelyn Flores 90 0.469 0.872 0.391
## 9 XXXTENTACION Jocelyn Flores 90 0.469 0.872 0.391
## 10 Lady Gaga Shallow - Radio Ed… 90 0.416 0.575 0.33
## # ℹ 125 more rows
## # ℹ 7 more variables: instrumentalness <dbl>, liveness <dbl>, loudness <dbl>,
## # speechiness <dbl>, tempo <dbl>, valence <dbl>, cluster <int>