Multiclass supervised classification of Spotify tracks by genre using numerical audio features and scikit-learn.
This project addresses music genre classification as a multiclass supervised classification problem. Given the numerical audio features of a Spotify track, the objective is to predict its genre from a set of 114 balanced classes.
The dataset consists of 114,000 tracks sourced from the Spotify Tracks Genre Dataset (Kaggle). Four scikit-learn classifiers are trained and compared on a stratified held-out test set. Performance is evaluated using accuracy, precision, recall, F1-score, and a confusion matrix.
Best result: Random Forest — 29.18% accuracy on the test set.
Source: Spotify Tracks Genre Dataset — Kaggle
| Property | Value |
|---|---|
| Total tracks | 114,000 |
| Total columns | 21 |
| Target classes | 114 genres, balanced (~1,000 tracks per class) |
| Missing values | None |
| Duplicate rows | None |
| Feature | Description |
|---|---|
popularity |
Track popularity score (0–100) |
duration_ms |
Duration in milliseconds |
danceability |
Suitability for dancing (0.0–1.0) |
energy |
Perceptual intensity and activity (0.0–1.0) |
key |
Estimated musical key (0–11) |
loudness |
Overall loudness in dB |
mode |
Modality: major (1) or minor (0) |
speechiness |
Presence of spoken words (0.0–1.0) |
acousticness |
Likelihood of being acoustic (0.0–1.0) |
instrumentalness |
Likelihood of containing no vocals (0.0–1.0) |
liveness |
Presence of a live audience (0.0–1.0) |
valence |
Musical positiveness (0.0–1.0) |
tempo |
Estimated tempo in BPM |
time_signature |
Estimated beats per bar |
Target variable: track_genre — one of 114 mutually exclusive genre labels.
Text columns (track_name, artists, album_name, track_id) were excluded from model input, as they do not represent audio signal and would not generalise to unseen tracks.
The notebooks support two methods:
Option 1 — automatic download via kagglehub (default):
import kagglehub
path = kagglehub.dataset_download("thedevastator/spotify-tracks-genre-dataset")
print("Path to dataset files:", path)Option 2 — manual download:
Download the CSV from Kaggle and place it at:
data/spotify_genre_classification.csv
If this local file is present, the notebooks use it directly; otherwise they fall back to kagglehub.
spotify-genre-classification/
│
├── data/ # Local dataset directory (not tracked by git)
│ └── spotify_genre_classification.csv
│
├── notebooks/
│ ├── 01_eda.ipynb # Exploratory Data Analysis
│ └── 02_modeling.ipynb # Preprocessing, model training, and evaluation
│
├── presentation/
│ └── Spotify_Genre_Classification.pptx # 10-slide project presentation
│
├── requirements.txt
└── README.md
The EDA notebook verifies dataset integrity (shape, data types, missing values, duplicate rows) and examines the distribution of all 14 numerical features across the top genres. The class distribution was confirmed to be balanced, with approximately 1,000 tracks per genre.
A key observation from the EDA is that while some genres exhibit visually distinguishable feature profiles — for example, acoustic tracks tend toward high acousticness and low energy, whereas electronic genres show the inverse — a substantial proportion of genre pairs overlap considerably in feature space. This finding motivated the evaluation of both linear and non-linear classifiers.
To keep training computationally manageable, a stratified sample of 20,000 tracks was drawn from the full 114,000-track dataset. Stratified sampling preserves the original genre proportions, ensuring no class is over- or under-represented in the working subset.
The sample was partitioned into a training set (75%, 15,000 tracks) and a test set (25%, 5,000 tracks), using stratified splitting to maintain class balance in both partitions. A fixed random_state was applied throughout to ensure reproducibility.
StandardScaler was applied to the features used by Logistic Regression and K-Nearest Neighbors:
- Logistic Regression relies on gradient-based optimisation, which is sensitive to differences in feature magnitude.
- KNN computes Euclidean distances, which are distorted when features operate on different scales.
Random Forest is scale-invariant — its splits are based on rank thresholds rather than absolute values — and was therefore trained on unscaled data.
All four classifiers were trained on the same training set and evaluated on the same held-out test set. Evaluation metrics include overall accuracy, per-class precision, recall and F1-score, and a confusion matrix computed over the 10 most frequent genres.
Four classifiers were selected to cover different learning paradigms:
| Model | Paradigm | Rationale |
|---|---|---|
DummyClassifier |
Baseline | Predicts the most frequent class regardless of input. Establishes the performance lower bound for the task (~0.88% for 114 balanced classes). |
LogisticRegression |
Linear | Simple linear classifier. Included to assess whether a linear decision boundary is sufficient to separate genres in the 14-dimensional feature space. |
KNeighborsClassifier (k=5) |
Distance-based | Non-parametric classifier that assigns labels based on nearest neighbours. Captures local similarity in the audio feature space. |
RandomForestClassifier (n_estimators=100) |
Ensemble | Ensemble of decision trees capable of learning non-linear relationships between features. Expected to outperform linear models given the complex, overlapping class structure observed during EDA. |
| Model | Accuracy |
|---|---|
| Dummy Classifier (baseline) | 0.88% |
| K-Nearest Neighbors (k = 5) | 14.42% |
| Logistic Regression | 18.80% |
| Random Forest (100 trees) | 29.18% ✓ |
| Genre | Precision | Recall | F1-score |
|---|---|---|---|
| comedy | 0.89 | 0.75 | 0.81 |
| grindcore | 0.75 | 0.86 | 0.80 |
| honky-tonk | 0.78 | 0.70 | 0.74 |
| emo | 0.00 | 0.00 | 0.00 |
| electronic | 0.06 | 0.02 | 0.03 |
Macro-average: Precision 0.28 · Recall 0.29 · F1 0.28
Weighted average: F1 ≈ 0.28
Random Forest achieved the highest accuracy (29.18%), outperforming all other evaluated classifiers. Its advantage over Logistic Regression (18.80%) and KNN (14.42%) is consistent with the overlapping class structure identified during EDA: the relationship between audio features and genre labels is non-linear, favouring an ensemble approach over a linear decision boundary.
Although 29.18% may appear modest, the task involves distinguishing among 114 balanced classes — a considerably more demanding setting than binary classification, where chance-level performance is approximately 0.88%. All trained models substantially outperform random prediction.
Per-class analysis reveals that genres with acoustically distinctive profiles — such as comedy, grindcore, and honky-tonk — are classified with substantially higher F1-scores. Genres that overlap with adjacent styles in feature space (e.g., emo, electronic) produce lower scores. The confusion matrix confirms that misclassifications are concentrated within acoustically similar genre families rather than randomly distributed, suggesting that the primary performance ceiling is the inherent similarity among subgenres.
1. Clone the repository
git clone https://github.com/Claffyhill/spotify-genre-ml.git
cd spotify-genre-ml2. Install dependencies
pip install -r requirements.txtDependencies:
pandas
numpy
scikit-learn
matplotlib
seaborn
kagglehub
jupyter
Launch Jupyter and execute the notebooks in order:
jupyter notebook| Step | Notebook | Description |
|---|---|---|
| 1 | notebooks/01_eda.ipynb |
Data integrity checks, class distribution, feature distributions, separability analysis |
| 2 | notebooks/02_modeling.ipynb |
Stratified subsampling, train/test split, feature scaling, model training, accuracy comparison, classification report, confusion matrix |
The dataset is downloaded automatically on first run via kagglehub. To use a local copy instead, place the CSV at data/spotify_genre_classification.csv before running the notebooks.
The following extensions could be explored in subsequent iterations of this project:
- Hyperparameter tuning: systematic search over Random Forest parameters (
n_estimators,max_depth,min_samples_leaf) to improve classification performance. - Feature engineering: construction of interaction features or the incorporation of aggregated metadata to enrich the audio-based representation.
- Additional ensemble methods: evaluation of Gradient Boosting variants on the same train/test partition.
- Neural network classifiers: exploration of shallow feed-forward architectures to assess whether increased model capacity improves performance on the harder-to-classify genres.
University of Cagliari · Machine Learning · Academic Year 2025/2026