Este conjunto de datos contiene 114.000 canciones de Spotify que abarcan 114 géneros musicales únicos, recopiladas a través de la API Web de Spotify. Cada pista incluye un conjunto de características de audio calculadas por el motor interno de análisis de audio de Spotify.
##Fuente: https://www.kaggle.com/datasets/saichaitanyareddyai/spotify-tracks-dataset-audio-features ##Archivo: spotify-tracks-dataset-detailed.csv (19.43 MB)
##Importación de la base de datos
Base_spotify <- read_csv(
"C:/Users/Juan_Cruz/Desktop/Carrera de especialización en estadística para las ciencias de salud/Multivariado/spotify-tracks-dataset-detailed.csv"
) %>%
rename(
id_cancion = track_id,
artistas = artists,
nombre_album = album_name,
nombre_cancion = track_name,
genero_musical = track_genre,
popularidad = popularity,
duracion_ms = duration_ms,
explicito = explicit,
bailabilidad = danceability,
energia = energy,
tonalidad = key,
sonoridad = loudness,
modo = mode,
presencia_habla = speechiness,
acusticidad = acousticness,
instrumentalidad = instrumentalness,
vivacidad = liveness,
valencia = valence,
tempo = tempo,
compas = time_signature
)
## Rows: 114000 Columns: 20
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (5): track_id, artists, album_name, track_name, track_genre
## dbl (14): popularity, duration_ms, danceability, energy, key, loudness, mode...
## lgl (1): explicit
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
glimpse(Base_spotify)
## Rows: 114,000
## Columns: 20
## $ id_cancion <chr> "5SuOikwiRyPMVoIQDJUgSV", "4qPNDBW1i3p13qLCt0Ki3A", "…
## $ artistas <chr> "Gen Hoshino", "Ben Woodward", "Ingrid Michaelson;ZAY…
## $ nombre_album <chr> "Comedy", "Ghost (Acoustic)", "To Begin Again", "Craz…
## $ nombre_cancion <chr> "Comedy", "Ghost - Acoustic", "To Begin Again", "Can'…
## $ popularidad <dbl> 73, 55, 57, 71, 82, 58, 74, 80, 74, 56, 74, 69, 52, 6…
## $ duracion_ms <dbl> 230666, 149610, 210826, 201933, 198853, 214240, 22940…
## $ explicito <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALS…
## $ bailabilidad <dbl> 0.676, 0.420, 0.438, 0.266, 0.618, 0.688, 0.407, 0.70…
## $ energia <dbl> 0.4610, 0.1660, 0.3590, 0.0596, 0.4430, 0.4810, 0.147…
## $ tonalidad <dbl> 1, 1, 0, 0, 2, 6, 2, 11, 0, 1, 8, 4, 7, 3, 2, 4, 2, 1…
## $ sonoridad <dbl> -6.746, -17.235, -9.734, -18.515, -9.681, -8.807, -8.…
## $ modo <dbl> 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0,…
## $ presencia_habla <dbl> 0.1430, 0.0763, 0.0557, 0.0363, 0.0526, 0.1050, 0.035…
## $ acusticidad <dbl> 0.0322, 0.9240, 0.2100, 0.9050, 0.4690, 0.2890, 0.857…
## $ instrumentalidad <dbl> 1.01e-06, 5.56e-06, 0.00e+00, 7.07e-05, 0.00e+00, 0.0…
## $ vivacidad <dbl> 0.3580, 0.1010, 0.1170, 0.1320, 0.0829, 0.1890, 0.091…
## $ valencia <dbl> 0.7150, 0.2670, 0.1200, 0.1430, 0.1670, 0.6660, 0.076…
## $ tempo <dbl> 87.917, 77.489, 76.332, 181.740, 119.949, 98.017, 141…
## $ compas <dbl> 4, 4, 4, 3, 4, 4, 3, 4, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4,…
## $ genero_musical <chr> "acoustic", "acoustic", "acoustic", "acoustic", "acou…
Base_spotify <- Base_spotify %>%
mutate(
popularidad = as.numeric(popularidad),
duracion_ms = as.numeric(duracion_ms),
genero_musical = as.factor(genero_musical),
explicito = factor(
explicito,
levels = c(FALSE, TRUE),
labels = c("0", "1")
),
tonalidad = as.factor(tonalidad),
modo = as.factor(modo),
compas = as.factor(compas)
)
generos_seleccionados <- c(
"heavy-metal",
"tango", "reggaeton"
)
Base_spotify_reducida <- Base_spotify %>%
filter(genero_musical %in% generos_seleccionados)
Base_spotify_reducida %>%
count(genero_musical, sort = TRUE)
## # A tibble: 3 × 2
## genero_musical n
## <fct> <int>
## 1 heavy-metal 1000
## 2 reggaeton 1000
## 3 tango 1000
La base de datos contiene 104977 observaciones con 22 variables sin ningún dato faltante
| Diccionario de variables | ||
| Base de datos Spotify | ||
| Variable | Tipo | Descripción |
|---|---|---|
| Variables descriptivas | ||
| id_cancion | carácter | Identificador único de la canción en Spotify. |
| artistas | carácter | Artista o artistas que interpretan la canción. |
| nombre_album | carácter | Nombre del álbum en el que se incluye la canción. |
| nombre_cancion | carácter | Nombre de la canción. |
| genero_musical | factor | Género musical asignado a la canción. |
| popularidad | numérico | Popularidad de la canción en Spotify medida en una escala de 0 (baja) a 100 (alta). |
| duracion_ms | numérico | Duración de la canción en milisegundos. |
| explicito | factor | Indica si la canción contiene contenido explícito: 0 = no contiene, 1 = contiene. |
| Variables de audio | ||
| bailabilidad | numérico | Grado en que una canción es adecuada para bailar. Rango: 0.0 a 1.0. |
| energia | numérico | Medida de intensidad y actividad percibida de la canción. Rango: 0.0 a 1.0. |
| tonalidad | factor | Tonalidad musical estimada de la canción, codificada de 0 a 11. |
| sonoridad | numérico | Sonoridad promedio de la canción en decibeles (dB). |
| modo | factor | Modalidad musical de la canción: 0 = menor, 1 = mayor. |
| presencia_habla | numérico | Medida de presencia de palabras habladas en la canción. Rango: 0.0 al 1.0. |
| acusticidad | numérico | Medida de confianza de que la canción sea acústica. Rango: 0.0 a 1.0. |
| instrumentalidad | numérico | Probabilidad de que la canción no contenga voces. Valores cercanos a 1.0 indican que la canción es instrumental. |
| vivacidad | numérico | Probabilidad de que la canción haya sido interpretada en vivo. Valores mayores a 0.8 sugieren registros en vivo. |
| valencia | numérico | Positividad emocional de la canción. Rango: 0.0 (triste) a 1.00 (feliz). |
| tempo | numérico | Velocidad estimada de la canción, medida en beats por minuto (BPM). |
| compas | factor | Compás estimado de la canción, representado como número de pulsos por compás. |
audio_vars <- Base_spotify_reducida %>%
select(
bailabilidad, energia, sonoridad, presencia_habla,
acusticidad, instrumentalidad, vivacidad,
valencia, tempo
)
desc_vars <- Base_spotify_reducida %>%
select(
id_cancion, artistas, nombre_album, nombre_cancion,
genero_musical, popularidad,
duracion_ms, explicito
)
skim(Base_spotify_reducida)
| Name | Base_spotify_reducida |
| Number of rows | 3000 |
| Number of columns | 20 |
| _______________________ | |
| Column type frequency: | |
| character | 4 |
| factor | 5 |
| numeric | 11 |
| ________________________ | |
| Group variables | None |
Variable type: character
| skim_variable | n_missing | complete_rate | min | max | empty | n_unique | whitespace |
|---|---|---|---|---|---|---|---|
| id_cancion | 0 | 1 | 22 | 22 | 0 | 2998 | 0 |
| artistas | 0 | 1 | 2 | 171 | 0 | 834 | 0 |
| nombre_album | 0 | 1 | 1 | 94 | 0 | 1127 | 0 |
| nombre_cancion | 0 | 1 | 1 | 107 | 0 | 2329 | 0 |
Variable type: factor
| skim_variable | n_missing | complete_rate | ordered | n_unique | top_counts |
|---|---|---|---|---|---|
| explicito | 0 | 1 | FALSE | 2 | 0: 2705, 1: 295 |
| tonalidad | 0 | 1 | FALSE | 12 | 2: 363, 7: 342, 9: 338, 4: 308 |
| modo | 0 | 1 | FALSE | 2 | 1: 1575, 0: 1425 |
| compas | 0 | 1 | FALSE | 4 | 4: 2712, 3: 222, 5: 44, 1: 22 |
| genero_musical | 0 | 1 | FALSE | 3 | hea: 1000, reg: 1000, tan: 1000, aco: 0 |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| popularidad | 0 | 1 | 23.32 | 19.15 | 0.00 | 16.00 | 21.00 | 27.00 | 98.00 | ▇▇▁▁▁ |
| duracion_ms | 0 | 1 | 216054.29 | 67673.31 | 56600.00 | 174210.75 | 204654.50 | 243646.50 | 1534315.00 | ▇▁▁▁▁ |
| bailabilidad | 0 | 1 | 0.57 | 0.17 | 0.09 | 0.45 | 0.56 | 0.72 | 0.96 | ▁▅▇▆▃ |
| energia | 0 | 1 | 0.66 | 0.25 | 0.04 | 0.45 | 0.71 | 0.87 | 1.00 | ▁▃▃▆▇ |
| sonoridad | 0 | 1 | -6.94 | 3.47 | -27.63 | -8.87 | -6.00 | -4.32 | -0.79 | ▁▁▂▆▇ |
| presencia_habla | 0 | 1 | 0.09 | 0.08 | 0.02 | 0.04 | 0.06 | 0.11 | 0.57 | ▇▁▁▁▁ |
| acusticidad | 0 | 1 | 0.34 | 0.38 | 0.00 | 0.00 | 0.13 | 0.79 | 1.00 | ▇▁▁▁▃ |
| instrumentalidad | 0 | 1 | 0.08 | 0.21 | 0.00 | 0.00 | 0.00 | 0.01 | 0.97 | ▇▁▁▁▁ |
| vivacidad | 0 | 1 | 0.23 | 0.20 | 0.01 | 0.10 | 0.15 | 0.30 | 0.99 | ▇▃▁▁▁ |
| valencia | 0 | 1 | 0.54 | 0.22 | 0.04 | 0.37 | 0.55 | 0.71 | 0.97 | ▂▆▇▇▅ |
| tempo | 0 | 1 | 120.01 | 29.12 | 50.96 | 97.00 | 116.71 | 135.04 | 214.02 | ▁▇▆▂▁ |
# 1. Crear base analítica sin NA
datos_pca <- Base_spotify_reducida %>%
select(
genero_musical,
bailabilidad, energia, sonoridad, presencia_habla,
acusticidad, instrumentalidad, vivacidad,
valencia, tempo
) %>%
drop_na()
audio_vars <- datos_pca %>%
select(-genero_musical)
# 2. Correlaciones
cor_matrix <- cor(audio_vars)
corrplot(cor_matrix, method = "color", type = "upper", tl.cex = 0.8)
# 3. Adecuación para PCA
cortest.bartlett(cor_matrix, n = nrow(audio_vars))
## $chisq
## [1] 9388.559
##
## $p.value
## [1] 0
##
## $df
## [1] 36
# 4. PCA
pca_model <- prcomp(audio_vars, center = TRUE, scale. = TRUE)
summary(pca_model)
## Importance of components:
## PC1 PC2 PC3 PC4 PC5 PC6 PC7
## Standard deviation 1.6248 1.3347 1.0478 1.0053 0.91908 0.88823 0.64524
## Proportion of Variance 0.2933 0.1979 0.1220 0.1123 0.09386 0.08766 0.04626
## Cumulative Proportion 0.2933 0.4913 0.6133 0.7256 0.81943 0.90709 0.95335
## PC8 PC9
## Standard deviation 0.57300 0.30255
## Proportion of Variance 0.03648 0.01017
## Cumulative Proportion 0.98983 1.00000
fviz_eig(pca_model, addlabels = TRUE)
# 5. Loadings
loadings <- as.data.frame(pca_model$rotation)
loadings %>%
rownames_to_column("variable") %>%
select(variable, PC1, PC2)
## variable PC1 PC2
## 1 bailabilidad -0.02211139 0.65051734
## 2 energia -0.57618984 -0.07758220
## 3 sonoridad -0.52528240 0.16118951
## 4 presencia_habla -0.08723601 0.24556986
## 5 acusticidad 0.54583553 0.08936697
## 6 instrumentalidad 0.23465093 -0.20370207
## 7 vivacidad -0.05885484 -0.31903619
## 8 valencia 0.08063737 0.57332486
## 9 tempo -0.14498575 -0.06749146
# 6. Scores
pca_scores <- as.data.frame(pca_model$x) %>%
mutate(genero_musical = datos_pca$genero_musical)
# 7. Visualización PCA por género
ggplot(pca_scores, aes(PC1, PC2, color = genero_musical)) +
geom_point(alpha = 0.5, size = 1.8) +
theme_minimal()
# 8. Clustering
vars_scaled <- scale(audio_vars)
fviz_nbclust(vars_scaled, kmeans, method = "wss")
fviz_nbclust(vars_scaled, kmeans, method = "silhouette")
# 8. Clustering con K = 3
set.seed(123)
kmeans_model <- kmeans(
vars_scaled,
centers = 3,
nstart = 25
)
# 10. Agregar clusters a las bases
pca_scores$cluster <- factor(kmeans_model$cluster)
datos_pca$cluster <- factor(kmeans_model$cluster)
# 11. Tamaño de cada cluster
datos_pca %>%
count(cluster) %>%
mutate(prop_porcentaje = round(n / sum(n) * 100, 1))
## # A tibble: 3 × 3
## cluster n prop_porcentaje
## <fct> <int> <dbl>
## 1 1 1020 34
## 2 2 1000 33.3
## 3 3 980 32.7
# 12. Visualizar clusters sobre PC1 y PC2
ggplot(pca_scores, aes(x = PC1, y = PC2, color = cluster)) +
geom_point(alpha = 0.5, size = 1.8) +
theme_minimal() +
labs(
title = "Clusters acústicos proyectados sobre PC1 y PC2",
x = "PC1: energía acústica",
y = "PC2: bailabilidad / valencia",
color = "Cluster"
)
# 13. Relación entre cluster y género
cluster_genero <- datos_pca %>%
count(cluster, genero_musical) %>%
group_by(cluster) %>%
mutate(
prop = n / sum(n),
prop_porcentaje = round(prop * 100, 1)
) %>%
arrange(cluster, desc(prop))
cluster_genero
## # A tibble: 9 × 5
## # Groups: cluster [3]
## cluster genero_musical n prop prop_porcentaje
## <fct> <fct> <int> <dbl> <dbl>
## 1 1 reggaeton 947 0.928 92.8
## 2 1 heavy-metal 37 0.0363 3.6
## 3 1 tango 36 0.0353 3.5
## 4 2 heavy-metal 940 0.94 94
## 5 2 reggaeton 45 0.045 4.5
## 6 2 tango 15 0.015 1.5
## 7 3 tango 949 0.968 96.8
## 8 3 heavy-metal 23 0.0235 2.3
## 9 3 reggaeton 8 0.00816 0.8
## # A tibble: 3 × 10
## cluster bailabilidad energia sonoridad presencia_habla acusticidad
## <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 1.03 0.325 0.576 0.381 -0.425
## 2 2 -0.821 0.843 0.382 -0.220 -0.836
## 3 3 -0.233 -1.20 -0.989 -0.172 1.30
## # ℹ 4 more variables: instrumentalidad <dbl>, vivacidad <dbl>, valencia <dbl>,
## # tempo <dbl>
fviz_pca_biplot(
pca_model,
geom.ind = "point",
habillage = pca_scores$cluster,
addEllipses = TRUE,
label = "var",
repel = TRUE
)