Machine Learning Music Genre Classification Project

Machine Learning project 16

Machine Learning Music Genre Classification Project

Build and evaluate a complete music genre classification workflow with reproducible Python code, explicit metrics, and honest limitations.

Explore Machine Learning training in VizagView all project ideas

Dataset and objective

Seeded synthetic track-level tempo, energy, danceability, and acousticness values for four illustrative genres and grouped artists.

Skills practised

  • Audio-feature tables
  • Grouped splitting
  • Leakage control
  • Multiclass evaluation

Requirements

  • Python 3.10 or later
  • A terminal or command prompt
  • python -m pip install numpy pandas scikit-learn
  • About 45-60 minutes to build and review

Machine Learning workflow

  1. Data: Seeded synthetic track-level tempo, energy, danceability, and acousticness values for four illustrative genres and grouped artists.
  2. Preprocessing: GroupShuffleSplit keeps each synthetic artist entirely in training or test data to reduce artist leakage.
  3. Model: RandomForestClassifier learns nonlinear feature profiles across the four labels.
  4. Evaluation: Per-genre precision, recall, and F1 on artists absent from training.

Complete Python code

Save the code as ml_music_genre_classification.py. The random state and data handling are included so the result can be reproduced and reviewed.

"""Classify music genres from synthetic, track-level audio features."""

from __future__ import annotations

import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report
from sklearn.model_selection import GroupShuffleSplit


def make_demo_features(tracks_per_genre: int = 120, random_state: int = 42) -> pd.DataFrame:
    rng = np.random.default_rng(random_state)
    profiles = {
        "classical": {"tempo": (95, 18), "energy": (0.30, 0.10), "danceability": (0.25, 0.09), "acousticness": (0.82, 0.10)},
        "jazz": {"tempo": (120, 22), "energy": (0.50, 0.12), "danceability": (0.50, 0.12), "acousticness": (0.62, 0.14)},
        "rock": {"tempo": (135, 20), "energy": (0.82, 0.09), "danceability": (0.52, 0.12), "acousticness": (0.16, 0.10)},
        "electronic": {"tempo": (128, 10), "energy": (0.78, 0.10), "danceability": (0.78, 0.09), "acousticness": (0.08, 0.06)},
    }
    rows = []
    for genre, profile in profiles.items():
        for index in range(tracks_per_genre):
            artist = f"{genre}_artist_{index // 6}"
            rows.append({
                "tempo": max(40, rng.normal(*profile["tempo"])),
                "energy": np.clip(rng.normal(*profile["energy"]), 0, 1),
                "danceability": np.clip(rng.normal(*profile["danceability"]), 0, 1),
                "acousticness": np.clip(rng.normal(*profile["acousticness"]), 0, 1),
                "artist": artist,
                "genre": genre,
            })
    return pd.DataFrame(rows)


def train_model(random_state: int = 42):
    data = make_demo_features(random_state=random_state)
    features = ["tempo", "energy", "danceability", "acousticness"]
    splitter = GroupShuffleSplit(n_splits=1, test_size=0.25, random_state=random_state)
    train_indices, test_indices = next(splitter.split(data[features], data["genre"], groups=data["artist"]))
    train, test = data.iloc[train_indices], data.iloc[test_indices]
    model = RandomForestClassifier(n_estimators=250, min_samples_leaf=3, random_state=random_state, n_jobs=-1)
    model.fit(train[features], train["genre"])
    predictions = model.predict(test[features])
    return model, test["genre"], predictions


def main() -> None:
    _, actual, predictions = train_model()
    print("Synthetic Music Genre Classification")
    print(classification_report(actual, predictions, zero_division=0))
    print("Artist-grouped splitting reduces leakage between tracks by the same synthetic artist.")
    print("Real genre labels are subjective and require licensed audio plus robust feature extraction.")


if __name__ == "__main__":
    main()

How the pipeline works

GroupShuffleSplit keeps each synthetic artist entirely in training or test data to reduce artist leakage.

RandomForestClassifier learns nonlinear feature profiles across the four labels. Per-genre precision, recall, and F1 on artists absent from training.

Run the project

  1. Create and activate a virtual environment.
  2. Install the dependencies with python -m pip install numpy pandas scikit-learn.
  3. Run python ml_music_genre_classification.py.
  4. Review every printed metric together with the limitation below; a single score never proves deployment readiness.

How to interpret the evaluation

Classification projects report class-aware metrics so majority classes do not hide weak performance. Regression projects report errors in target units and include R-squared or a simple baseline where appropriate. Always verify the split strategy matches how new data will arrive.

Accuracy, ethics, and safety limits

Features, artists, and labels are synthetic. Real genres overlap and labels can be subjective; audio requires licensed files and a consistent feature-extraction pipeline.

Ways to extend the project

Extract features from licensed clips, use group cross-validation, add spectrogram models, support multilabel genres, and measure performance across recording conditions.

Continue learning Machine Learning

Try the next project, return to the Softenant project library, or explore the Machine Learning course in Vizag for guided data preparation, model evaluation, and portfolio feedback.