Moosic is a startup that curates playlists by hand, but their team of music experts can't keep up with growing demand. This project explores whether Spotify's numerical audio features (danceability, energy, valence, tempo) are enough to automatically group ~5,000 songs into clusters that could serve as playlists. We test DBSCAN for outlier detection and K-Means for the actual clustering, and evaluate the results both statistically (silhouette scores) and by manually inspecting the generated playlists.
This was a capstone project completed during a Data Science & AI training program at WBS Coding School and was presented to the cohort in March 2026.
- Source: Spotify Web API - Audio Features
- Size: 5,235 songs, 19 columns (5,112 after deduplication)
- Key Features Used: danceability, energy, valence, tempo
- Limitations: No genre labels, no lyrics, no user listening data. Only numerical audio characteristics computed by Spotify from the raw audio signal.
- DBSCAN found no meaningful outliers. The data is too uniformly distributed across the 4 selected features for density-based methods to find structure. Every eps setting either produces one giant cluster or arbitrary splits with negative silhouette scores.
- K-Means with k=46 produces musically coherent playlists. Clusters clearly separate calm jazz/classical tracks from high-energy dance music and upbeat feel-good songs.
- Silhouette score of 0.21 with only 4.8% of songs having negative silhouette values (likely misplacements). Moderate but consistent.
- Feature selection was the most impactful decision. Reducing from 9 to 4 features (removing skewed and redundant ones) improved playlist coherence significantly.
- Audio features capture energy, not genre. Songs with similar audio profiles end up together even if they're from completely different genres. Jazz and classical mix, reggaeton sits next to rock.
- Programming: Python
- Libraries: pandas, numpy, scikit-learn, matplotlib, seaborn
- Machine Learning: K-Means Clustering, DBSCAN, MinMaxScaler, Silhouette Analysis
- Environment: Jupyter Notebook
music_playlist_clustering_spotify/
|
|- README.md # This file
|- moosic_playlist_clustering.ipynb # Full analysis notebook
|
|- data/
|- spotify_5000_songs.csv # Original dataset (5,235 songs)
The notebook contains the following key plots:
- Audio feature distributions showing the spread of all 11 features across the dataset
- Correlation heatmap revealing which features overlap and which are independent
- Elbow and silhouette plots for choosing the optimal number of clusters
- Silhouette blade plot showing how well each individual song fits its assigned cluster
- Main Analysis: Open moosic_playlist_clustering.ipynb to see the full workflow from EDA through clustering to evaluation
- Data: The dataset is included in the
/datafolder - Run the Code: Open the notebook in Jupyter and run all cells top to bottom
- Dependencies: Standard data science stack (pandas, numpy, scikit-learn, matplotlib, seaborn)
- Audio features don't capture genre. Two songs can have nearly identical danceability, energy, valence, and tempo but feel completely different because of vocals, lyrics, or cultural context. Jazz and classical end up in the same cluster, reggaeton sits next to rock.
- No control over cluster sizes. K-Means produced clusters ranging from 41 to 235 songs. The ~50 song editorial target would require a post-processing step (splitting/merging) that's outside the scope of this prototype.
- Moderate silhouette scores (0.21). The data doesn't have sharp natural groupings. The clusters are meaningful when inspected, but the boundaries are soft rather than crisp.
- Missing data dimensions. Genre labels, user listening behavior, or lyrics would all add signal that pure audio features can't provide.
- GitHub: Robin-Reiche