Dataset Walkthrough

Περιγραφή Dataset & Μεταβλητών


Το Dataset

Το “Spotify Tracks Dataset” αντλήθηκε από το Kaggle σε μορφή CSV. Κάθε γραμμή του αντιπροσωπεύει ένα μεμονωμένο τραγούδι (καλύπτοντας συνολικά 125 διαφορετικά μουσικά είδη), ενώ οι στήλες καταγράφουν τα χαρακτηριστικά του.


Σκοπός του Case Study

Στην ανάλυση που θα κάνουμε, επιδιώκουμε να εντοπίσουμε αυτόματες ομαδοποιήσεις τραγουδιών με βάση τα ακουστικά τους χαρακτηριστικά, παρακάμπτοντας τις κλασικές ταμπέλες των μουσικών ειδών όπως τις γνωρίζουμε. Μέσα από αυτή την εξερεύνηση, στοχεύουμε στον ορισμό νέων, στατιστικά τεκμηριωμένων κατηγοριών, που προκύπτουν από μια βαθύτερη κατανόηση του dataset.


Data Preview

rmarkdown::paged_table(track_data)


Μεταβλητές ανά Θεματική Περιοχή

🆔 Ταυτότητα & Πληροφορίες

  • track_id (string): Μοναδικός κωδικός αναγνώρισης κάθε τραγουδιού στο Spotify.
  • track_name (string): Ο τίτλος του τραγουδιού.
  • artists (string): Ονόματα των καλλιτεχνών (πολλαπλοί καλλιτέχνες διαχωρίζονται με ερωτηματικό).
  • album_name (string): Ο τίτλος του άλμπουμ στο οποίο περιλαμβάνεται το τραγούδι.
  • track_genre (string): Η κατηγορία μουσικού είδους (genre) στην οποία ανήκει το τραγούδι.

⚡ Ενέργεια & Ρυθμός

  • danceability (numeric): Καταλληλότητα για χορό (0: ελάχιστα κατάλληλο, 1: απόλυτα κατάλληλο).
  • energy (numeric): Το επίπεδο έντασης και δραστηριότητας του κομματιού (0: ήρεμο, 1: πολύ ενεργητικό).
  • tempo (double): Ο ρυθμός του τραγουδιού μετρημένος σε χτύπους ανά λεπτό (BPM).
  • loudness (double): Η συνολική ηχητική ένταση του τραγουδιού σε ντεσιμπέλ (dB).
  • time_signature (int): Ο αριθμός των χτύπων σε κάθε μέτρο (συνήθως μεταξύ 3 και 7).
  • duration_ms (int): Η διάρκεια του τραγουδιού σε χιλιοστά του δευτερολέπτου (ms).

🎹 Τεχνικά & Ηχητικά Χαρακτηριστικά

  • acousticness (double): Πιθανότητα το τραγούδι να είναι ακουστικό (1 = πολύ υψηλή πιθανότητα).
  • instrumentalness (double): Πιθανότητα το τραγούδι να μην έχει φωνητικά (1 = καθαρά οργανική μουσική).
  • speechiness (double): Παρουσία ομιλούμενου λόγου: >0.66 (ομιλία), 0.33-0.66 (μίξη ομιλίας/μουσικής), <0.33 (μουσική).
  • liveness (double): Πιθανότητα το τραγούδι να είναι ζωντανή ηχογράφηση (υψηλή τιμή = live εκτέλεση).
  • key (int): Η μουσική κλίμακα (τόνος) του τραγουδιού. Η τιμή -1 υποδηλώνει άγνωστη κλίμακα.
  • mode (boolean): Η τροπικότητα της κλίμακας: 1 = Μείζονα (ευχάριστος ήχος), 0 = Ελάσσονα (μελαγχολικός ήχος).

🌟 Διάθεση & Δημοτικότητα

  • valence (double): Η συναισθηματική θετικότητα του κομματιού (Υψηλή: χαρούμενο, Χαμηλή: λυπημένο/αρνητικό).
  • popularity (int): Δείκτης δημοτικότητας βάσει αριθμού και πρόσφατης δραστηριότητας αναπαραγωγών.
  • explicit (boolean): Ένδειξη για ύπαρξη ακατάλληλου περιεχομένου (True: Ναι, False: Όχι/Άγνωστο).


Ανάλυση μέσω Ιεραρχικής Συσταδοποίησης

Μεθοδολογία

Σε πρώτη φάση, θα χρειαστεί να προβούμε σε εκκαθάριση των δεδομέων του dataset, καθώς ενδέχεται να υπάρχουν διπλότυπες εγγραφές οιοποίες αλλοιώνουν τα αποτελέσματα της ανάλυσής μας. Ωστόσο, η απαλοιφή των διπλοτύπων δεν είναι εύκολη, καθώς έχουμε κομμάτια που αφορούν το ίδιο τραγούδι αλλά καταχωρήθηκαν ως διαφορετικά επειδή ανήκουν σε άλλα άλμπουμ ή επανακυκλοφόρησαν. Επομένως, θα θεωρήσουμε ως κλειδί για τη μοναδικότητα τον συνδυασμό καλλιτέχνη και ονόματος τραγουδιού, κρατώντας κάθε φορά το πιο δημοφιλές αντίγραφο του ίδιου τραγουδιού. Παρακάτω φαίνεται ο συνολικός αριθμός μοναδικών εγγραφών (η εκκαθάριση έγινε από τις αρχικές 114.000 εγγραφές)

library(tidyverse)

track_data = unique(track_data) 
spotify_final_clean <- track_data %>%
  arrange(desc(popularity)) %>%
  distinct(track_name, artists, .keep_all = TRUE)

# Έλεγχος: Πόσες γραμμές έφυγαν;
nrow(track_data) - nrow(spotify_final_clean)
## [1] 32656
clean_tracks <- spotify_final_clean

Επίσης, λόγω της αυξημένης πολυπλοκότητας της ιεραρχικής συσταδοποίησης, θα χρειαστεί να δουλέψουμε σε ένα δείγμα από το συνολικό καθαρό dataset, ενδεικτικά αποτελούμενο από 5.000 εγγραφές. Σε αυτό το σημείο για να αποφύγουμε περαιτέρω υπολογισμούς θα απομονώσουμε τα τεχνικά χαρακτηριστικά των κομματιών, τα οποία παρουσιάζουν το βασικό ενδιαφέρον για την ανάλυσή μας. Επιπλέον θα εκτελέσουμε μία κανονικοποίηση στις τιμές των μεταβλητών, καθώς θέλουμε να μην υπάρχουν ανομοιομορφίες που “φουσκώνουν” τις αποστάσεις που θα υπολογίσουμε.

set.seed(123)
spotify_sample <- spotify_final_clean 
spotify_sample <- na.omit(spotify_sample)%>% 
  sample_n(5000)

clustering_vars <- spotify_sample %>%
  select(danceability, energy, loudness, speechiness, 
         acousticness, instrumentalness, liveness, valence, tempo)%>%
  scale()
Δημιουργία Συστάδων

Έχοντας έτοιμο το δείγμα από το Dataset, πάνω στο οποίο θα κάνουμε συσταδοποίηση, εξάγουμε το πρώτο διάγραμμα των συστάδων που προκύπτουν.

distances = dist(clustering_vars, method = "euclidean")
clusterTracks = hclust(distances, method = "ward.D2") 

plot(clusterTracks, 
     main = "Διάγραμμα Ιεραρχικής Συσταδοποίησης", 
     col.main = "#1DB954",  
     col.lab = "#1DB954",   
     col.axis = "#1DB954",  
     sub = "",              
     ann = TRUE)                        

Όπως παρατηρούμε έχουμε υπερβολικά πολλά επίπεδα συστάδων. Σε ένα τέτοιο δείγμα και λόγω της ευρείας ποικιλίας μουσικών ειδών που επιχειρούμε να αναδείξουμε, χωρίς όμως να εμβαθύνουμε σε πολύ εξειδικευμένες κατηγορίες, θα επιλέξουμε να εξάγουμε 7 clusters. Παρακάτω, φαίνεται το πλήθος παρατηρήσεων που συγκεντρώνονται ανά cluster.


library(knitr)
library(kableExtra)
library(dplyr)
library(plotly)
library(tidyr)

clusters = cutree(clusterTracks, k = 7)

spotify_sample$cluster <- as.factor(clusters)



# Υπολογισμός μέσων τιμών ανά cluster
cluster_profile <- spotify_sample %>%
  group_by(cluster) %>%
  summarise(across(c(danceability, energy, loudness, speechiness, 
                     acousticness, instrumentalness, liveness, valence, tempo), 
                   mean, na.rm = TRUE))



summary_horizontal <- spotify_sample %>%
  count(cluster) %>%
  mutate(cluster = paste("Cluster", cluster))%>% 
  pivot_wider(names_from = cluster, values_from = n)


summary_horizontal %>%
  kbl(align = "c") %>%
  kable_styling(full_width = TRUE, 
                bootstrap_options = c("condensed")) %>%
  row_spec(0, 
           background = "#14833B", 
           color = "white", 
           bold = TRUE)
Cluster 1 Cluster 2 Cluster 3 Cluster 4 Cluster 5 Cluster 6 Cluster 7
255 1960 837 1047 549 303 49

Για καλύτερη εικόνα του προφίλ τιμών που λαμβάνουν οι μεταβλητές ανά cluster, δημιουργήθηκε πίνακας με τις μέσες τιμές κάθε μεταβλητής για όλα τα clusters που οπτικοποιείται στην διαδραστική προβολή που ακολουθεί.

rmarkdown::paged_table(cluster_profile)
# 1. Προετοιμασία των δεδομένων - Παραμένει το ίδιο
nodes <- colnames(cluster_profile)[-1]

create_radar_trace <- function(cluster_id) {
  row_data <- cluster_profile %>% filter(cluster == cluster_id) %>% select(-cluster)
  as.numeric(row_data)
}

# 2. ΚΑΤΑΣΚΕΥΗ ΤΟΥ PLOT - ΕΔΩ ΕΙΝΑΙ Η ΑΛΛΑΓΗ
# Αρχικοποιούμε το fig ΧΩΡΙΣ type και fill για να μην δημιουργηθεί trace ακόμα
fig <- plot_ly() 

# Προσθέτουμε τα 10 clusters
for(i in 1:7) {
  fig <- fig %>% add_trace(
    type = 'scatterpolar',     # Μεταφέραμε το type εδώ
    fill = 'toself',           # Μεταφέραμε το fill εδώ
    r = c(create_radar_trace(i), create_radar_trace(i)[1]), 
    theta = c(nodes, nodes[1]),
    name = paste("Cluster", i),
    visible = (i == 1), 
    marker = list(color = "#1DB954"),
    fillcolor = 'rgba(29, 185, 84, 0.4)'
  )
}

# 3. Δημιουργία του "Menu" - Παραμένει το ίδιο
dropdown_buttons <- lapply(1:7, function(i) {
  vis_list <- rep(FALSE, 7)
  vis_list[i] <- TRUE
  list(
    method = "restyle",
    args = list("visible", as.list(vis_list)),
    label = paste("Cluster", i)
  )
})

# 4. Τελική διαμόρφωση - Πρόσεξε το χρώμα στο font του μενού
fig <- fig %>% layout(
  title = list(text = "Cluster Explorer: Music DNA", font = list(color = "#1DB954", size = 20)),
  paper_bgcolor = "#191414",
  plot_bgcolor = "#191414",
  polar = list(
    bgcolor = "#191414",
    radialaxis = list(visible = T, range = c(0, 1), color = "gray"),
    angularaxis = list(color = "white")
  ),
  updatemenus = list(
    list(
      buttons = dropdown_buttons,
      direction = "down",
      showactive = TRUE,
      x = 0.1, y = 1.2,
      font = list(color = "#1DB954") 
    )
  )
)

fig
Σχολιασμός Clusters & Συμπεράσματα

Συνοπτικό Προφίλ Clusters

  • Cluster No 1

    Δυναμικό cluster με υψηλό liveness και tempo, που παραπέμπει σε ζωντανές, γρήγορες και έντονες ηχογραφήσεις. Πολύ χαμηλό loudness και instrumentalness, δίνοντας έμφαση στη φωνή χωρίς ψηφιακά όργανα. Συνδυασμός έντονης ενέργειας (energy) με χαμηλό valence, δημιουργώντας μια ατμόσφαιρα σοβαρή, «σκοτεινή» αλλά γεμάτη ένταση.

    Χαρακτηριστικά Κομμάτια

    spotify_sample %>% 
      filter(cluster == 1) %>% 
      slice_max(popularity, n = 5) %>% 
      select(track_name,artists,popularity)


  • Cluster No 2

    Χαρακτηρίζεται από μέγιστο tempo και υψηλή ενέργεια (energy), αποτελώντας την πιο γρήγορη και δυναμική ομάδα του δείγματος. Διαθέτει υψηλό valence και danceability, στοιχεία που παραπέμπουν σε ανεβαστική, ευδιάθετη και ρυθμική μουσική. Εμφανίζει ελάχιστο acousticness και instrumentalness, υποδηλώνοντας σύγχρονες παραγωγές.

    Χαρακτηριστικά Κομμάτια

    spotify_sample %>% 
      filter(cluster == 2) %>% 
      slice_max(popularity, n = 5) %>% 
      select(track_name,artists,popularity)


  • Cluster No 3

    Διακρίνεται για το υψηλό acousticness και το γρήγορο tempo, συνδυάζοντας φυσικούς ήχους με ταχύτητα στον ρυθμό. Η ενέργεια και το loudness παραμένουν σε χαμηλά επίπεδα, υποδεικνύοντας «ήσυχες» αλλά σταθερά ρυθμικές συνθέσεις. Με χαμηλό valence και σχεδόν μηδενικό instrumentalness, το cluster παραπέμπει σε ακουστικά, μελαγχολικά κομμάτια που εστιάζουν στη φωνή.

    Χαρακτηριστικά Κομμάτια

    spotify_sample %>% 
      filter(cluster == 3) %>% 
      slice_max(popularity, n = 5) %>% 
      select(track_name,artists,popularity)


  • Cluster No 4

    Διαθέτει πολύ υψηλό tempo και αυξημένη ενέργεια, προσφέροντας μια έντονη και γρήγορη ρυθμική βάση. Έχει ελάχιστο acousticness, instrumentalness και speechiness, στοιχείο που παραπέμπει σε σύγχρονες, αμιγώς ψηφιακές παραγωγές. Χαρακτηρίζεται από χαμηλό valence και loudness, δίνοντας έναν πιο συγκρατημένο ή «σοβαρό» τόνο παρά τη μεγάλη ταχύτητα.

    Χαρακτηριστικά Κομμάτια

    spotify_sample %>% 
      filter(cluster == 4) %>% 
      slice_max(popularity, n = 5) %>% 
      select(track_name,artists,popularity)


  • Cluster No 5

    Εμφανίζει σημαντικά υψηλό instrumentalness και tempo, παραπέμποντας σε ορχηστρικά ή ηλεκτρονικά κομμάτια χωρίς φωνητικά. Η ενέργεια είναι υψηλή, αλλά το loudness και το valence παραμένουν χαμηλά, δημιουργώντας μια αίσθηση «έντονης αλλά ψυχρής» ατμόσφαιρας. Σχεδόν μηδενικό speechiness και acousticness, υπογραμμίζοντας τον αμιγώς ψηφιακό και μη λεκτικό χαρακτήρα της συγκεκριμένης ομάδας.

    Χαρακτηριστικά Κομμάτια

    spotify_sample %>% 
      filter(cluster == 5) %>% 
      slice_max(popularity, n = 5) %>% 
      select(track_name,artists,popularity)


  • Cluster No 6

    Συνδυάζει εξαιρετικά υψηλό acousticness και instrumentalness, θυμίζοντας ορχηστρική ή ακουστική μουσική χωρίς φωνητικά. Παρά το υψηλό tempo, η ενέργεια και το loudness παραμένουν σε πολύ χαμηλά επίπεδα, προσφέροντας μια ήρεμη αλλά ρυθμική αίσθηση. Με σχεδόν μηδενικό danceability και valence, το cluster αυτό εστιάζει στην ατμοσφαιρική ακρόαση.

    Χαρακτηριστικά Κομμάτια

    spotify_sample %>% 
      filter(cluster == 6) %>% 
      slice_max(popularity, n = 5) %>% 
      select(track_name,artists,popularity)


  • Cluster No 7

    Κυριαρχείται από πολύ υψηλό speechiness και acousticness, υποδηλώνοντας κομμάτια με έμφαση στον λόγο (εν προκειμένω Podcasts) και φυσικό ήχο. Διαθέτει γρήγορο tempo και σημαντική liveness, προσφέροντας μια αίσθηση «ζωντανής» και ταχείας ροής στην ακρόαση. Η χαμηλή ένταση (loudness) και το μηδενικό instrumentalness επιβεβαιώνουν την επικέντρωση στη φωνή έναντι της ψηφιακής παραγωγής.

    Χαρακτηριστικά Κομμάτια

    spotify_sample %>% 
      filter(cluster == 7) %>% 
      slice_max(popularity, n = 5) %>% 
      select(track_name,artists,popularity)

Συμπεράσματα

Η ανάλυση απέδειξε ότι η ιεραρχική συσταδοποίηση μπορεί να χαρτογραφήσει τη μουσική βάσει ακουστικού “DNA”, παρακάμπτοντας τις παραδοσιακές ταμπέλες των ειδών.

Βασικά Ευρήματα

  • Mood vs Genre: Τα clusters ομαδοποιούν τα τραγούδια βάσει “διάθεσης”. Το Cluster 2 αποτελεί την πιο Mainstream ανεβαστική/χορευτική ζώνη, ενώ το Cluster 6 την “Focus” ζώνη, ανεξαρτήτως μουσικού είδους.

  • Αυτοματοποιημένος Διαχωρισμός: Ο αλγόριθμος απομόνωσε με ακρίβεια τον ομιλούμενο λόγο (Cluster 7 - Podcasts) και την ορχηστρική μουσική (Cluster 6).

  • Ακουστική Αντίθεση: Επιβεβαιώθηκε η σταθερή αρνητική συσχέτιση μεταξύ φυσικότητας (Acousticness) και έντασης (Energy/Loudness).

Πρακτική Εφαρμογή

Μεγάλη σημασία έχει να δούμε πώς γίνεται να εκμεταλλευτούμε τα ευρήματα της ανάλυσης μέσω συσταδοποίησης. Σε πρακτικό επίπεδο, θα μπορούσε να προταθεί η αυτόματη δημιουργία λιστών για συγκεκριμένες δραστηριότητες (π.χ. Gym από το Cluster 2, Study από το Cluster 6). Επιπλέον, μπορούν να γίνονται προτάσεις τραγουδιών με παρόμοιο ηχητικό DNA για αύξηση του user engagement. Τέλος, η αναγνώριση των χρηστών που προτιμούν περιεχόμενο λόγου (Cluster 7) θα μπορούσε δυνητικά να είναι χρήσιμη για εξατομικευμένες καμπάνιες.