Book Recommendation System with PySpark
Book Recommendation System with PySpark
of
Big Data Analytics Lab [CSE 3145]
July-November 2025
SCHOOL OF COMPUTER SCIENCE & ENGINEERING
Manipal
29/10/2025
CERTIFICATE
This is to certify that the project titled Book Recommendation System using
PySpark is a record of the bonafide work done by Hrithiq Gupta(230962300),
Arnav Sahu (230962306) submitted in partial fulfilment of the requirements for
the award of the Degree of Bachelor of Technology ([Link].) in COMPUTER
SCIENCE & ENGINEERING (ARTIFICIAL INTELLIGENCE & MACHINE
LEARNING) of Manipal Institute of Technology, Manipal, Karnataka, (A
Constituent Institute of Manipal Academy of Higher Education), during the
academic year 2025-2026.
CHAPTER 2: METHODOLOGY
CHAPTER 4: CONCLUSION
REFERENCES
CHAPTER 1
INTRODUCTION
In today's world, we're constantly bombarded with choices, especially when it comes to books.
With thousands of titles available online, finding your next great read can feel overwhelming.
That's where book recommendation systems come in handy. Our project tackles this problem by
building a recommendation system that suggests books users might actually enjoy, based on the
Goodbooks-10K dataset - a real collection of book ratings from users just like us.
We decided to use collaborative filtering for this project, which is basically a fancy way of
saying we're learning from what people have rated in the past
For our implementation, we tried out three different approaches: Alternating Least Squares
(ALS), Singular Value Decomposition (SVD), and k-Nearest Neighbors (kNN). Each has its own
strengths - some are more accurate, some are easier to explain, and some run faster. By
comparing all three, we could figure out which works best for our dataset.
We're dealing with millions of ratings here. Running this on a regular laptop would take forever,
and that is why PySpark is used, which lets us spread the work across multiple computers at
once. Spark handles all the coordination and even deals with failures automatically, which means
our system could actually work in the real world, not just in a classroom setting.
Using Pyspark means our solution is scalable. Traditional approaches work fine for small
datasets, but when you're processing millions of user ratings, you need distributed computing.
Spark's in-memory processing makes everything much faster, and its fault-tolerant design means
the system doesn't crash if one node fails. This practical approach ensures our recommendation
system could handle real user traffic if deployed on a platform like Goodreads or Amazon.
1.1 Objectives
The Goodbooks-10K dataset is sourced from Kaggle and contains reading preferences
collected from Goodreads, a popular social cataloging website for books [1]. The dataset
provides a realistic testbed for recommendation algorithms as it reflects actual user behavior
with natural rating distributions and sparsity patterns commonly encountered in real-world
systems.
Data Source: Goodbooks-10K Dataset (Kaggle)
Citation: Zygmunt Zając, "Goodbooks-10K Dataset," Kaggle, 2017
URL: [Link]
The dataset comprises five CSV files containing different aspects of user-book interactions.
The primary file, [Link], contains approximately 6 million ratings with three columns:
book_id (integer identifier for books), user_id (integer identifier for users), and rating (float
value between 1.0 and 5.0 indicating user preference). These ratings serve as the target
variable for our predictive models. The dataset exhibits high sparsity (approximately 99.9%),
meaning most user-book pairs have no rating, which is typical in recommendation scenarios
where users interact with only a small fraction of available items.
The [Link] file provides metadata for 10,000 books including 23 features such as title,
authors, original_publication_year, average_rating, ratings_count, and distributions across
rating levels (ratings_1 through ratings_5). These features are primarily numeric (publication
year, rating counts) and categorical (authors, language_code). The metadata enables content-
based feature engineering to supplement collaborative filtering signals, particularly for
handling cold-start scenarios where items have few ratings.
Additional files include to_read.csv (user reading wishlists), book_tags.csv (genre/category
tags assigned to books), and [Link] (mapping of tag IDs to readable names). These files
provide auxiliary information about user interests and book characteristics that could be
incorporated in hybrid recommendation approaches.
This chapter describes the end-to-end data analytics pipeline developed for building the book
recommendation system. The pipeline consists of four main stages: preprocessing, exploratory
analysis, model building, and evaluation. Each stage is implemented using PySpark to leverage
distributed computing capabilities. Figure 2.1 illustrates the flow of data through various stages.
Fig. 2.1: Flow of data through various stages of the analytics pipeline
2.1 Preprocessing
Preprocessing is essential to ensure data quality and prepare features suitable for machine
learning algorithms. The ratings data required minimal cleaning as it contains explicit user-book-
rating triplets without missing values. However, several preprocessing steps were necessary to
handle the books metadata and create informative features for the models.
Data Loading and Type Casting: The [Link] file is loaded using PySpark's DataFrame API
with schema inference. User IDs and book IDs are cast to integer type, while ratings are cast to
double precision floating point to enable arithmetic operations. The distributed nature of Spark
allows this file to be partitioned across cluster nodes for parallel processing.
Duplicate Removal: Although rare, duplicate (user, book) pairs are identified using
dropDuplicates() transformation and removed to ensure each user rates each book at most once.
This prevents model bias from repeated observations.
Missing Value Handling: The books metadata contains missing values in several columns. For
the original_publication_year feature, missing values are imputed using the median year to
preserve distribution properties. This is implemented using PySpark's Imputer transformer with
median strategy. For categorical features like authors and language_code, missing values are
filled with the string "unknown" to create an explicit missing category.
Feature Engineering: Several derived features are created to capture user behavior patterns and
book characteristics:
1. User Statistics: For each user, we compute total rating count (user_rating_count) and
average rating (user_rating_mean). These capture user activity level and rating tendency
(generous vs. critical raters).
2. Book Statistics: For each book, we compute total rating count (book_rating_count)
and average rating (book_rating_mean). These capture book popularity and quality.
3. Author Encoding: The authors field contains over 4,000 unique values. To prevent
excessive dimensionality, we identify the top 200 most frequently occurring authors and map all
others to an "other" category. This reduces noise while preserving information about popular
authors.
Feature Engineering: Several derived features are created to capture user behavior patterns and
book characteristics:
1. User Statistics: For each user, we compute total rating count (user_rating_count) and
average rating (user_rating_mean). These capture user activity level and rating tendency
(generous vs. critical raters).
2. Book Statistics: For each book, we compute total rating count (book_rating_count) and
average rating (book_rating_mean). These capture book popularity and quality.
3. Author Encoding: The authors field contains over 4,000 unique values. To prevent
excessive dimensionality, we identify the top 200 most frequently occurring authors and map all
others to an "other" category. This reduces noise while preserving information about popular
authors.
Categorical Encoding: Categorical features (authors, language_code) are encoded using a two-
stage pipeline implemented with PySpark MLlib transformers:
1. StringIndexer: Converts string categories to numeric indices based on frequency (most
frequent category gets index 0). The handleInvalid="keep" parameter ensures previously unseen
categories are mapped to a special index rather than causing errors.
2. OneHotEncoder: Converts categorical indices to binary vectors using one-hot
encoding. For a feature with n categories, this creates n-1 binary columns (one column is
redundant due to linear dependency). The sparse vector representation is memory-efficient for
high-cardinality features.
Normalization: Numeric features exhibit different scales (e.g., rating counts range from 1 to
thousands while ratings range from 1 to 5). To prevent features with large magnitudes from
dominating distance calculations, we apply StandardScaler which transforms each feature to
have zero mean and unit variance. This is implemented using PySpark's StandardScaler
transformer with withStd=True and withMean=False (mean centering is not feasible with sparse
vectors).
Vector Assembly: All engineered features (user statistics, book statistics, encoded categories)
are combined into a single feature vector using VectorAssembler. This creates a features column
containing a sparse vector representation suitable for machine learning algorithms.
Exploratory data analysis (EDA) provides insights into data distribution patterns that inform
modeling decisions. All analyses are performed on sampled data (5% sample) using PySpark
aggregations to avoid collecting the entire 6-million-row dataset to the driver node, which would
cause memory issues.
Rating Distribution: The distribution of ratings is computed using groupBy aggregation on the
rating column. Results show ratings are not uniformly distributed. Approximately 57% of ratings
are 4 or 5 stars, indicating positive bias where users preferentially rate books they enjoyed. This
skewed distribution affects model training as the model may learn to predict high ratings more
frequently. The distribution visualization clearly shows this pattern.
Fig. 2.2: Rating distribution with respect to Count
This skew toward high ratings is important because it means our model might naturally lean
toward predicting higher scores.
User Activity Distribution: To understand user engagement patterns, we compute ratings per
user using groupBy("user_id").count(). The histogram reveals a heavy-tailed distribution
characteristic of power-law behavior. The median user has only 8 ratings while the mean is 112
ratings, indicating a small fraction of highly active users contribute disproportionately to the
dataset. This has implications for model training as sparse users (few ratings) provide limited
Book Popularity Distribution: Similarly, ratings per book are computed using
groupBy("book_id").count(). The histogram in Fig 2.4 shows book popularity also follows a
power-law distribution. A few blockbuster titles have tens of thousands of ratings while many
books have fewer than 10 ratings. This long-tail distribution is typical of recommendation
scenarios and motivates the use of matrix factorization tec
hniques that can discover latent patterns even for less popular items.
Data Quality Assessment: We verify that ratings are within valid range [1.0, 5.0] and no users
or books have only a single rating (which would prevent proper train-test splitting). These checks
are implemented using filter conditions and aggregations in PySpark.
1. For each user with at least 2 ratings, randomly select 1 rating for the test set
2. All remaining ratings go to the training set
3. Users with only 1 rating are excluded from testing (no way to validate)
This results in approximately 80% of data in training and 20% in test, with every test user having
training history. The random selection uses a fixed seed (RANDOM_SEED=100) for
reproducibility. This approach is implemented using PySpark's Window function with
row_number() to assign a random order to each user's ratings.
where the summation is over observed ratings and λ is the regularization parameter. The
optimization alternates between fixing user factors and solving for item factors (via least
squares), then fixing item factors and solving for user factors. This iterative process converges to
a local minimum.
For each parameter combination, the training set is split into k folds, and the model is trained on
k-1 folds and validated on the remaining fold. The average validation RMSE across folds is used
to select the best parameters. The parallelism parameter controls how many parameter
combinations are evaluated in parallel, leveraging Spark's distributed computing.
Distributed Training: ALS is implemented using Spark's distributed matrix operations. The
user factors and item factors are represented as RDDs (Resilient Distributed Datasets) partitioned
across cluster nodes. Each alternating step involves distributed joins and aggregations. The
algorithm is inherently parallelizable as updating each factor row is independent given the fixed
complementary factors.
where U (m×k) contains user factors, Σ (k×k) is a diagonal matrix of singular values, and V
(n×k) contains item factors. The k largest singular values capture the most important patterns in
the data.
Implementation using PySpark MLlib: Since the full user-item matrix is too large to fit in
memory, we use Spark's RowMatrix to represent the matrix in distributed form. The
computeSVD method performs distributed singular value decomposition:
1. Each row of the rating matrix (one user's ratings for all items) is represented as a sparse
vector
2. Vectors are collected into a RowMatrix RDD distributed across nodes
3. computeSVD performs matrix operations distributedly and returns U, Σ, V The number of
factors k is set to 50 (SVD_K=50). The resulting item factors V are used to compute predictions:
for user i, the predicted score for item j is the dot product of user i's latent factors and item j's
latent factors.
Difference from ALS: While both are matrix factorization techniques, SVD directly computes
the decomposition via eigendecomposition, whereas ALS uses iterative optimization. SVD is
deterministic (always produces the same result for given data) while ALS depends on
initialization and may converge to different local minima.
Higher dot product indicates items have similar latent characteristics. For each item, we
precompute the top k=50 most similar items (KNN_NEIGHBORS=50) to speed up prediction.
Implementation: The kNN algorithm is implemented in Python using NumPy arrays for item
factors and a Counter object for aggregating scores. While not fully distributed like ALS and
SVD, the computation benefits from Spark's parallelism during the factor computation stage.
where rᵢ is the true rating and r̂ᵢ is the predicted rating. Lower RMSE indicates better accuracy.
RMSE penalizes large errors more heavily due to squaring. It is implemented using PySpark's
RegressionEvaluator with metricName="rmse".
NDCG@K (Normalized Discounted Cumulative Gain): NDCG measures ranking quality with
position bias (items ranked higher are more valuable):
where relᵢ is the relevance (1 if relevant, 0 otherwise) at position i, and IDCG is the ideal DCG
(best possible ranking). NDCG ranges from 0 to 1, with 1 being perfect ranking.
The implementation uses Python functions (precision_at_k, recall_at_k, ndcg_at_k) that operate
on dictionaries mapping user IDs to lists of recommended item IDs. These functions are applied
after collecting recommendations from Spark to the driver.
CHAPTER 3
RESULT ANALYSIS
This chapter presents the experimental results, comparing the three implemented algorithms
(ALS, SVD, kNN) across multiple evaluation metrics. Results demonstrate the trade-offs
between different approaches and identify the best-performing model for the book
recommendation task
Note: kNN does not provide explicit rating predictions, so RMSE is not applicable
Why RMSE Matters: RMSE directly measures how accurately the model predicts numerical
ratings. Lower RMSE means predictions are closer to actual user preferences, which is important
for applications that display predicted ratings to users.
ALS Performance: ALS achieved the lowest RMSE of 0.879, indicating predictions are
typically within 0.88 stars of actual ratings. The regularized matrix factorization successfully
captures user-item interaction patterns despite 99.9% sparsity.
SVD Performance: SVD achieved RMSE of 0.891, slightly higher than ALS. The difference
(0.012) is relatively small, suggesting both matrix factorization approaches are comparably
effective. SVD's deterministic nature (no random initialization) makes results reproducible, but
the iterative optimization in ALS allows for more flexible modeling of non-linearities.
Why Ranking Metrics Matter: In recommendation systems, users typically see only a small
number of recommendations (top-10). What matters most is whether these top items are relevant,
not whether rating predictions are numerically precise. Precision and recall measure
recommendation relevance, while NDCG additionally considers ranking order.
ALS Ranking Performance: ALS achieved Precision@10 of 0.342, meaning 34.2% of
recommended books were relevant (rated ≥3 by user). Recall@10 of 0.187 indicates the model
successfully included 18.7% of all relevant books in the top-10. NDCG@10 of 0.412 shows the
model places more relevant items earlier in the ranking. These results demonstrate ALS
effectively identifies relevant books even for unseen test users.
SVD Ranking Performance: SVD achieved Precision@10 of 0.318 and Recall@10 of 0.174,
both slightly lower than ALS. The NDCG@10 of 0.398 similarly indicates slightly worse
ranking quality. The performance gap suggests that ALS's iterative optimization provides better
calibration of latent factors for the recommendation task, despite SVD being theoretically
elegant.
kNN Ranking Performance: kNN achieved Precision@10 of 0.285 and Recall@10 of 0.156,
lower than both matrix factorization approaches. NDCG@10 of 0.361 is also the lowest. This
suggests that neighborhoodbased similarity from item factors (computed via SVD) is less
effective than directly optimizing for rating prediction. However, kNN's local, instance-based
nature provides interpretability ("because you liked Book X, we recommend similar Book Y").
Coverage Analysis: Coverage measures what fraction of items can be recommended (have been
included in at least one user's top-K recommendations). ALS achieved 87.3% coverage, meaning
8,730 out of 10,000 books were recommended to at least one user. This high coverage indicates
the model provides diverse recommendations across the catalog rather than always
recommending blockbusters. SVD achieved 83.1% coverage and kNN achieved 71.4% coverage.
The lower coverage for kNN reflects its reliance on direct item similarity, which may not
connect disparate parts of the catalog.
Popularity Bias: Analysis shows that ALS slightly favors popular books. The top-10
recommendations include books with median rating count of 1,847, compared to overall median
of 598. This is expected as popular books have more training signal. Techniques like
regularization and adversarial training could mitigate this bias if desired.
Rating Scale Interpretation: Users interpret rating scales differently (some users rarely give 5
stars, others frequently do). The models partially account for this via user factors
(user_rating_mean feature), but individual user calibration is limited by data sparsity.
CHAPTER 4
CONCLUSION
This project successfully developed a scalable book recommendation system using collaborative
filtering techniques on the Goodbooks-10K dataset. Three algorithms were implemented and
compared: Alternating Least Squares (ALS), Singular Value Decomposition (SVD), and k-
Nearest Neighbors (kNN), all leveraging PySpark's distributed computing framework for
efficient large-scale processing.
Key Findings:
ALS emerged as the best-performing model, achieving RMSE of 0.879 for rating prediction and
Precision@10 of 0.342 for recommendation quality. The model's iterative optimization and
regularization effectively handled the dataset's extreme sparsity (99.9%), learning robust latent
representations of user preferences and book characteristics. The use of cross-validation for
hyperparameter tuning (rank, regularization parameter, iterations) was crucial for achieving
optimal performance, demonstrating the importance of systematic model selection.
SVD provided competitive performance (RMSE 0.891, Precision@10 0.318) with faster training
time (8.7s vs 14.3s for ALS). The small accuracy gap suggests that for this dataset, the
theoretical elegance and computational efficiency of SVD make it a viable alternative,
particularly for applications requiring frequent model updates. The deterministic nature of SVD
also provides reproducibility advantages.
kNN underperformed on ranking metrics (Precision@10 0.285) compared to matrix factorization
approaches, consistent with literature findings that model-based methods handle sparsity better
than memory-based methods. However, kNN's interpretability ("you liked X, so we recommend
similar Y") offers value for explaining recommendations and building user trust.
Scope for Future Work: Several directions could extend this work:
1. Hybrid Models: Combine collaborative filtering with content-based filtering using book
metadata (genres, authors, descriptions). This would improve cold-start handling and
potentially increase accuracy by incorporating item features.
2. Deep Learning: Explore neural collaborative filtering approaches (neural matrix
factorization, neural autoencoder) that can learn non-linear user-item interactions. These
have shown improved accuracy in some domains.
3. Context-Aware Recommendations: Incorporate contextual information like time of day,
device type, or current reading list to make situation-specific recommendations.
4. Multi-Armed Bandit: Implement online learning where recommendations adapt in real-
time based on user clicks, balancing exploration (trying new recommendations) and
exploitation (recommending known-good items).
5. Explainable Recommendations: Develop methods to generate natural language
explanations ("Recommended because you liked Author X" or "Fans of Genre Y also
enjoyed this book") that increase user trust and engagement.
6. Cross-Domain Recommendations: Extend to recommend not just books but other media
(movies, music) based on reading preferences, leveraging transfer learning across
domains.
7. Fairness and Diversity: Implement techniques to ensure recommendations are fair across
demographic groups and promote diversity of authors and perspectives rather than
reinforcing echo chambers.
This project demonstrates that collaborative filtering with distributed computing provides an
effective, scalable solution for book recommendations. The combination of matrix factorization
algorithms (ALS, SVD) and distributed processing (PySpark, Hadoop) enables learning from
millions of user interactions while maintaining training times suitable for production
deployment. The comprehensive evaluation using both rating accuracy (RMSE) and ranking
quality (Precision, Recall, NDCG) provides a complete picture of model performance. While
limitations exist, particularly around cold start and popularity bias, the system provides a strong
foundation for real-world recommendation applications, with clear directions for future
enhancement through hybrid approaches, deep learning, and context-aware methods.
REFERENCES