Book Ratings Prediction

Machine Learning MLflow SHAP R Shiny XGBoost/LightGBM
Architecture
Book ratings prediction pipeline architecture diagram
R Shiny Dashboard
R Shiny dashboard with predict-a-book what-if tab
Try the Live Dashboard

Predicts Goodreads book ratings from book metadata and sparse NY Times Best Sellers signals. The primary dataset is a Kaggle Goodreads catalog (~1.85M books), filtered to ~342k books with at least 100 total ratings and deduplicated by title/author. NYT Best Sellers weekly overview snapshots are joined in via a deterministic ISBN-10↔13 conversion — only a small fraction of the catalog matches (most books were never bestsellers), handled with an is_bestseller flag rather than treated as a data-quality problem.

A Makefile-orchestrated pipeline (ingest → clean → enrich → features → train → evaluate → score) trains and MLflow-tracks six models — Ridge, Lasso, ElasticNet, Random Forest, XGBoost, and LightGBM — and compares them on RMSE/MAE/R², with SHAP explainability and error analysis surfacing which features (rating volume, author/publisher history, bestseller status) drive predictions.

Results are served through an R Shiny dashboard with four tabs: model performance, SHAP feature drivers, a data-quality/catalog explorer with a book-detail drill-through, and a "Predict a Book" what-if tool. Since the trained model only knows a book's rating from signals it accrues after publication, that last tab takes hypothetical engagement inputs and scores them with the actual trained XGBoost booster — exported to portable JSON and ported to R, not re-implemented, and verified to match the Python pipeline's predictions to the decimal.

Leakage-aware by design: the per-star rating-distribution features (pct_1_star…pct_5_star) are excluded from the model entirely, since they mathematically reconstruct Rating (Goodreads' own weighted average of those counts) and would leak the target if used as predictors. The R port also replicates a subtler detail exactly: scikit-learn's ColumnTransformer one-hot output is sparse, and XGBoost treats its implicit zero entries as missing rather than literal 0 — true during training, so predict_helpers.R matches it or predictions silently drift.
Built with
Python Pandas scikit-learn XGBoost LightGBM MLflow SHAP R R Shiny rsconnect

Six-model MLflow comparison with SHAP explainability; the winning XGBoost booster is exported and ported to R so the live Shiny "Predict a Book" tab can score new inputs without a Python runtime at request time.