A machine learning project to predict whether a song will become a hit based on its audio features, using Logistic Regression and XGBoost with SHAP interpretability.
This project analyzes Spotify audio features to predict hit songs. We compare interpretable (Logistic Regression) and high-performance (XGBoost) models, and use SHAP (SHapley Additive exPlanations) to understand which musical characteristics contribute to a song's success.
- Comprehensive Data Pipeline: Automated data loading, cleaning, and labeling
- Dual Modeling Approach: Both interpretable and high-performance models
- Advanced Interpretation: SHAP analysis for feature importance and effects
- Production-Quality Code: Well-documented Jupyter notebooks with visualizations
- Handles Class Imbalance: Specialized techniques for imbalanced datasets
This project uses two Kaggle datasets:
- Spotify Tracks Dataset - Large collection of songs with audio features
- Billboard/Spotify Top 100 - Chart-topping hits for labeling
- Danceability: How suitable for dancing (0-1)
- Energy: Intensity and activity measure (0-1)
- Loudness: Overall loudness in dB
- Speechiness: Presence of spoken words (0-1)
- Acousticness: Confidence measure of acoustic sound (0-1)
- Instrumentalness: Predicts whether track has vocals (0-1)
- Liveness: Detects presence of audience (0-1)
- Valence: Musical positivity/happiness (0-1)
- Tempo: Overall tempo in BPM
hit-song-prediction/
│
├── notebooks/ # Jupyter notebooks (main workflow)
│ ├── 00_Setup_and_Installation.ipynb
│ ├── 01_Week1_Data_Setup_EDA.ipynb
│ ├── 02_Week2_Baseline_Modeling.ipynb
│ └── 03_Week3_XGBoost_SHAP.ipynb
│
├── data/
│ ├── raw/ # Original datasets (gitignored)
│ │ ├── tracks.csv
│ │ └── top100_tracks.csv
│ └── processed/ # Cleaned datasets
│ └── hits_dataset.csv
│
├── models/ # Trained models
│ ├── baseline_logreg.pkl
│ ├── final_xgboost.pkl
│ ├── scaler.pkl
│ └── shap_values.npy
│
├── figures/ # Generated visualizations
│ ├── tracks_by_year.png
│ ├── feature_distributions.png
│ ├── correlation_matrix.png
│ ├── logreg_confusion_matrix.png
│ ├── logreg_coefficients.png
│ ├── xgboost_confusion_matrix.png
│ ├── model_comparison.png
│ ├── shap_feature_importance.png
│ └── shap_summary_detailed.png
│
├── src/ # Python scripts (optional)
├── reports/ # Final reports and presentations
│
├── requirements.txt # Python dependencies
├── .gitignore # Git ignore rules
└── README.md # This file
- Python 3.8 or higher
- pip package manager
- (Optional) Conda for environment management
# 1. Clone the repository
git clone <repository-url>
cd hit-song-prediction
# 2. Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# 3. Install dependencies
pip install -r requirements.txt
# 4. Launch Jupyter
jupyter notebook# 1. Clone and navigate
git clone <repository-url>
cd hit-song-prediction
# 2. Create conda environment
conda create -n hits python=3.10
conda activate hits
# 3. Install dependencies
pip install -r requirements.txt
# 4. Launch Jupyter
jupyter notebook-
Visit Kaggle and download:
- "Spotify Tracks Dataset" → Save as
data/raw/tracks.csv - "Spotify Top 100" or "Billboard Hot 100" → Save as
data/raw/top100_tracks.csv
- "Spotify Tracks Dataset" → Save as
-
Verify files are in correct location:
ls data/raw/ # Should show: tracks.csv top100_tracks.csv
-
Setup Environment
jupyter notebook
-
Run Setup Notebook
- Open
notebooks/00_Setup_and_Installation.ipynb - Run all cells to verify installation
- Open
-
Verify Data
- Ensure datasets are in
data/raw/ - Run verification cells in setup notebook
- Ensure datasets are in
Execute notebooks in order:
Notebook: 01_Week1_Data_Setup_EDA.ipynb
- Load Spotify tracks and Top 100 datasets
- Create HIT/NON-HIT labels through dataset matching
- Handle missing values and outliers
- Explore feature distributions
- Generate correlation analysis
- Save processed dataset
Outputs:
data/processed/hits_dataset.csvfigures/tracks_by_year.pngfigures/feature_distributions.pngfigures/correlation_matrix.png
Notebook: 02_Week2_Baseline_Modeling.ipynb
- Train/test split with stratification
- Feature scaling (StandardScaler)
- Dummy baseline for comparison
- Logistic Regression with class balancing
- Comprehensive evaluation metrics
- Coefficient interpretation
Outputs:
models/baseline_logreg.pklmodels/scaler.pklfigures/logreg_confusion_matrix.pngfigures/logreg_roc_curve.pngfigures/logreg_pr_curve.pngfigures/logreg_coefficients.png
Notebook: 03_Week3_XGBoost_SHAP.ipynb
- XGBoost with class imbalance handling
- Hyperparameter tuning (optional: set
SKIP_TUNING=Truefor faster run) - Model evaluation and comparison
- SHAP analysis for interpretability
- Feature importance visualization
- Generate presentation materials
Outputs:
models/final_xgboost.pklmodels/shap_values.npyfigures/xgboost_confusion_matrix.pngfigures/model_comparison.pngfigures/shap_feature_importance.pngfigures/shap_summary_detailed.pngfigures/shap_dependence_plots.png
| Metric | Logistic Regression | XGBoost | Improvement |
|---|---|---|---|
| Accuracy | 75-85% | 80-90% | +5-10% |
| Precision | 50-70% | 60-80% | +10-15% |
| Recall | 60-75% | 70-85% | +10-15% |
| F1 Score | 55-72% | 65-82% | +10-15% |
| ROC-AUC | 0.75-0.85 | 0.80-0.92 | +5-10% |
Note: Actual results depend on dataset quality and class imbalance ratio
Based on similar Spotify audio feature research:
-
Important Features for Hits:
- ✅ Danceability (+): More danceable songs tend to chart
- ✅ Energy (+): Energetic songs perform better
- ✅ Valence (+): Positive, happy songs are favored
- ❌ Acousticness (-): Less acoustic = more likely to chart
- ❌ Instrumentalness (-): Vocal tracks outperform instrumental
-
Model Comparison:
- Logistic Regression: Simple, interpretable, linear assumptions
- XGBoost: Captures non-linear patterns, higher performance
- SHAP bridges the gap: Makes XGBoost interpretable
-
Class Imbalance Challenge:
- Severe imbalance (~10-50:1 non-hits to hits)
- Addressed through
class_weightandscale_pos_weight - Focus on F1, Recall, and PR-AUC over accuracy
- Fuzzy Matching: Match hits across datasets using track name + artist
- Labeling Strategy:
- HIT (1): Appears in Top 100 dataset
- NON-HIT (0): Does not appear in Top 100
- Temporal Filtering: Focus on 2010-2020 (configurable)
- Missing Values: Drop rows with missing audio features
LogisticRegression(class_weight='balanced')Automatically adjusts weights inversely proportional to class frequencies.
scale_pos_weight = (# negative samples) / (# positive samples)
XGBClassifier(scale_pos_weight=scale_pos_weight)Gives more weight to minority class (hits) during training.
Primary Metrics (for imbalanced data):
- F1 Score: Harmonic mean of precision and recall
- Recall: Percentage of actual hits correctly identified
- PR-AUC: Precision-Recall Area Under Curve
Secondary Metrics:
- Accuracy: Overall correctness
- ROC-AUC: Discrimination ability
Why not just accuracy? With 95% non-hits, a model predicting "all non-hits" gets 95% accuracy but 0% recall!
SHAP (SHapley Additive exPlanations) explains predictions:
- Global Importance: Which features matter most overall
- Local Importance: Why a specific song was predicted as a hit
- Directional Effects: How feature values affect predictions
- Interactions: Complex relationships between features
In 01_Week1_Data_Setup_EDA.ipynb:
YEAR_START = 2015 # Change from default 2010
YEAR_END = 2023 # Change from default 2020In 01_Week1_Data_Setup_EDA.ipynb:
audio_features = [
'danceability', 'energy', 'valence', # Keep these
# Add or remove features as needed
]In 03_Week3_XGBoost_SHAP.ipynb:
SKIP_TUNING = True # Use default parameters (faster)
# Or reduce iterations:
n_iter = 10 # Default is 20In 02_Week2_Baseline_Modeling.ipynb:
TEST_SIZE = 0.3 # Default is 0.2 (20%)Problem: pip install fails for certain packages
Solution:
# Update pip first
pip install --upgrade pip
# Install problematic packages separately
pip install xgboost==2.0.0
pip install shap==0.42.0Problem: Column names don't match
Solution: Manually set column names in 01_Week1_Data_Setup_EDA.ipynb:
# After loading datasets, set these manually:
track_name_col = 'your_column_name'
artist_col = 'your_artist_column_name'Problem: Very few hits matched (< 50)
Solutions:
- Use fuzzy matching (uncomment fuzzy matching cell in Week 1)
- Try a different Top 100 dataset
- Lower matching threshold
Problem: Out of memory error during SHAP analysis
Solution: Reduce sample size in 03_Week3_XGBoost_SHAP.ipynb:
sample_size = min(500, len(X_test)) # Default is 1000Problem: Hyperparameter tuning takes too long
Solutions:
- Set
SKIP_TUNING = True - Reduce
n_iterfrom 20 to 10 - Use fewer CPU cores:
n_jobs=2instead ofn_jobs=-1
- Audio features only: Doesn't account for marketing, artist fame, timing, luck
- Temporal bias: Music trends change over time
- Limited scope: Only Spotify features, may miss cultural context
- Survivorship bias: Only includes songs released on Spotify
- Correlation ≠ Causation: Features are associated with hits, not causing them
- Class imbalance: Severe imbalance makes prediction challenging
- Generalization: Model trained on past hits may not predict future trends
- Feature engineering: Simple features, no interaction terms or temporal features
-
Feature Engineering
- Interaction terms (e.g., energy × danceability)
- Temporal features (month of release, day of week)
- Normalized features (percentiles within year)
-
Advanced Sampling
- SMOTE (Synthetic Minority Oversampling)
- ADASYN (Adaptive Synthetic Sampling)
- Ensemble with different sampling strategies
-
Additional Models
- Random Forest
- LightGBM
- Neural Networks
-
External Data
- Artist popularity metrics
- Lyrics sentiment analysis
- Social media trends
- Music video views
-
Temporal Modeling
- Time series analysis of music trends
- Seasonal effects
- Genre evolution over time
-
Deep Learning
- Audio spectrograms with CNNs
- Transformer models for music
- Multi-modal learning (audio + lyrics + metadata)
-
Deployment
- Web application for predictions
- API for real-time inference
- Dashboard for music industry professionals
If you use this project in your research or presentation, please cite:
Hit Song Prediction Using Spotify Audio Features
Machine Learning Course Project
[Your Name/Team], [University/Institution], [Year]
This project is for educational purposes. Dataset licenses:
- Spotify data: Check Kaggle dataset licenses
- Code: MIT License (if applicable)
- Datasets: Kaggle contributors for Spotify and Billboard datasets
- Libraries: scikit-learn, XGBoost, SHAP, pandas, seaborn
- Inspiration: Music information retrieval research community
For questions or issues:
- Open an issue on GitHub
- Contact: [Your Email]
- Course: [Course Name and Number]
Beyond the core 3-week curriculum, we've included advanced techniques:
Notebook: 04_Advanced_SMOTE_Sampling.ipynb
Explores advanced sampling methods for handling class imbalance:
- SMOTE (Synthetic Minority Over-sampling Technique)
- ADASYN (Adaptive Synthetic Sampling)
- Borderline-SMOTE
- SMOTE + Tomek Links (combined over/under-sampling)
Runtime: ~15 minutes
Key Insights:
- When SMOTE helps vs when class weighting is sufficient
- Trade-offs between precision and recall
- Comparison of all sampling strategies
Notebook: 05_Feature_Engineering.ipynb
Creates advanced features to boost model performance:
- Interaction Terms: energy×danceability, valence×energy, etc.
- Polynomial Features: Squared terms for non-linear relationships
- Domain-Specific Features: party_factor, acoustic_contrast
- Temporal Features: year_normalized, year_period
Runtime: ~10 minutes
Impact: Typically 2-5% improvement in F1 score
File: app.py
A beautiful web interface for making predictions!
Features:
- 🎯 Real-time hit prediction
- 📊 Interactive sliders for all audio features
- 📈 Probability visualization
- 🔍 Feature importance insights
- 💡 Model explanations
Launch the app:
streamlit run app.pyThen open your browser to http://localhost:8501
Screenshot Features:
- Adjust 9 audio feature sliders
- Get instant hit probability prediction
- View feature contributions
- See model performance metrics
- Access SHAP visualizations
pip install -r requirements.txtjupyter notebook
# Then run notebooks in order: 00 → 01 → 02 → 03jupyter notebook
# Run: 04 (SMOTE), 05 (Feature Engineering)streamlit run app.py
# Opens in browser at localhost:8501Core Notebooks:
- Setup: 5 minutes
- Week 1: 20 minutes
- Week 2: 15 minutes
- Week 3: 30-45 minutes (or 10 minutes with SKIP_TUNING=True)
Advanced Notebooks (Optional):
- SMOTE Sampling: 15 minutes
- Feature Engineering: 10 minutes
- Models:
models/final_xgboost.pkl,models/best_sampling_model.pkl - Best Figures:
figures/shap_feature_importance.png,figures/model_comparison.png - Datasets:
data/processed/hits_dataset.csv,data/processed/hits_dataset_engineered.csv - Web App: Interactive prediction interface
Happy Analyzing! 🎵🎶