🇬🇧 English · 🇬🇷 Ελληνικά
Semester project — University of Thessaly, Department of Electrical and Computer Engineering. Author: Evangelos Organtzoglou · January 2025
Two Jupyter notebooks that build book recommenders from public book-rating datasets, working through the classical approaches and then the neural ones. Version 1.0 is a single combined pipeline; version 2.0 is a wider second pass that adds exploratory analysis, a CNN content model and a neural collaborative filtering model.
Every recommender takes a free-text book title from the user, resolves it to a real title with fuzzy matching, and returns ranked suggestions.
| # | Approach | Notebook | Technique |
|---|---|---|---|
| 1 | Content-based (TF-IDF) | 1.0 | TF-IDF (1–2 grams) → TruncatedSVD 250 → cosine kNN |
| 2 | Content-based (counts) | 2.0 | CountVectorizer → full cosine similarity matrix |
| 3 | Collaborative (SVD) | 1.0 | scipy.sparse.linalg.svds, k = 15, on the user–item matrix |
| 4 | Collaborative (user kNN) | 1.0 | cosine kNN over user rating vectors, 30 neighbours |
| 5 | Collaborative (item–item) | 2.0 | Pearson correlation between book rating vectors |
| 6 | Collaborative (kNN + SVD) | 2.0 | TruncatedSVD 100 → cosine kNN, k = 20 |
| 7 | Autoencoder embeddings | 1.0 | Dense 256 bottleneck trained to reconstruct the feature matrix |
| 8 | CNN content model | 2.0 | multi-kernel Conv1D genre classifier → 128-d embeddings |
| 9 | Neural collaborative filtering | 2.0 | four embedding inputs → dense tower → predicted rating |
Notebook 1.0 also exposes a hybrid entry point that runs the content, autoencoder, SVD and kNN recommenders together and prints all four ranked lists side by side.
Headline numbers, with the scale each one is measured on:
| Model | Metric | Rating scale |
|---|---|---|
| Content-based, user-profile eval (2.0) | MSE 2.49 | 1–5 |
| Item–item Pearson CF (2.0) | MSE 4.03 | 0–10 |
| Item–item kNN on SVD-100 (2.0) | MSE 4.16 | 0–10 |
| SVD collaborative filtering (1.0) | MSE 62.31 | 0–10 |
| User-based kNN (1.0) | MSE 62.59 | 0–10 |
| CNN genre classifier (2.0) | val. binary accuracy 0.9917 | multi-label |
| Neural collaborative filtering (2.0) | MSE 0.1107, RMSE 0.3327, MAE 0.2581 | 0–1, normalised |
The NCF row is not directly comparable to the others. Its ratings are MinMax-scaled to [0, 1] before training, so its errors live on a 1/10-width scale. Rescaled onto the same 0–10 axis as the collaborative models, that MSE becomes ≈ 11.07 (RMSE ≈ 3.33) — worse than item–item CF, not thirty-six times better. The apparent win is a unit artefact.
The two MSE ≈ 62 figures from notebook 1.0 are also genuine, and their cause is known — see docs/RESULTS.en.md for the full discussion of both.
notebooks/
├── Recommender System 1.0.ipynb # first iteration — one combined pipeline
└── Recommender System 2.0.ipynb # second iteration — EDA, CNN, NCF
docs/
├── METHODS.en.md / METHODS.el.md # what each notebook does, step by step
├── RESULTS.en.md / RESULTS.el.md # metrics, how they were measured, caveats
├── DATA.en.md / DATA.el.md # datasets, where to get them, schemas
└── REFERENCES.md # papers and articles the work draws on
The notebooks do not ship with data — the rating datasets are large and belong to their original publishers.
git clone https://github.com/eorgantzoglou/Book-Recommender-System.git
cd Book-Recommender-System
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
jupyter labThen follow docs/DATA.en.md to download the datasets. Both notebooks read
from a data/ directory at the repository root:
books_data = pd.read_csv('data/cleaned_books_data.csv')Put the cleaned CSVs there and the notebooks run without any code edits. data/ is
gitignored, so nothing large gets committed by accident.
These are real defects and limitations in the code as submitted, kept here rather than quietly fixed so the notebooks stay faithful to what was handed in.
- Dead vectorizer (2.0). The second content model builds
count_2but then callscount.fit_transform(...)— refitting the first vectorizer.count_2is never used, and the first content recommender breaks if re-run afterwards, because its vocabulary has been replaced. - Ineffective fuzzy threshold (2.0).
find_best_titleis called withcutoff=0.75whilefuzz.partial_ratioreturns 0–100, so the guard never rejects anything. Any input matches something. - Truncated rating data (2.0). The collaborative sections use
merge_data[:40000]andnew_merge_data[:100000]— the first N rows, not a random sample. Results do not generalise to the full dataset. - Zero-filled user–item matrix (1.0). Unrated pairs are filled with
0and then fed tosvds, so the factorisation is fit against "rated 0" rather than "unknown". This is the direct cause of the MSE ≈ 62 results. - No stored output for three cells (2.0). The rating regressor's test MSE and the NCF training history were not saved, so those numbers cannot be quoted from the notebook.
Eleven papers and five articles informed the implementation. They are cited with DOIs and links in docs/REFERENCES.md. The PDFs are deliberately not redistributed here — several are published by ACM and Springer under terms that do not permit it.
Code and documentation are released under the MIT Licence. The datasets are not covered by it and are not included; see docs/DATA.en.md.