Four generations of recommender on 65K Amazon Electronics ratings — from a popularity baseline through user- and item-based KNN to matrix factorization. Tuned SVD wins, and stays personalized exactly where KNN breaks on sparse data.
Recommender systems are judged on data they will never see. The dataset here is 65,290 Amazon Electronics ratings spanning 1,540 users and 5,689 products — which sounds substantial until you multiply it out. Those users and products form roughly 8.76 million possible pairs, so the ratings that actually exist fill 0.7% of the matrix. Everything else is empty.
That sparsity is the whole problem, not a footnote to it. A model that scores well on the ratings it has seen is easy; the question is what happens for a user and a product that have never met. At 99.3% sparsity, that's almost every recommendation the system will ever make.
Four generations of recommender, each one answering a weakness in the last, all judged under an identical protocol:
Each model was scored on RMSE plus precision, recall and F1 at top-10 — error and ranking quality together, because a recommender that predicts ratings accurately can still put the wrong ten things on the page. Every family then went through GridSearchCV, so the comparison is between tuned models rather than defaults. Built with Surprise, scikit-learn and pandas.
Tuned SVD won on both axes — 0.8808 RMSE with precision@10 of 0.855. Item-item KNN followed at 0.9615, and user-user KNN trailed at roughly 1.00, barely distinguishable from predicting the average.
Tuning mattered, and it mattered unevenly. GridSearchCV moved item-item KNN from 0.9950 to 0.9615 and lifted its recall@10 from 0.845 to 0.878; searching SVD's epochs, learning rate and regularization produced the final 0.8808. The ordering of the model families held before and after tuning — hyperparameters sharpened each approach without rescuing the weaker ones.
On sparse data, KNN quietly stops personalizing. This is the finding that actually changed how I read the numbers. When a user has no rated neighbors — the common case at 99.3% sparsity — a neighborhood model has nothing to average over and falls back to a global mean. It still returns a prediction, and the RMSE still looks reasonable, but the recommendation has stopped being about that person. SVD's latent factors keep predictions individual even for pairs it never observed, which is why the gap widens exactly where recommendations matter most.
A metric can pass while the product fails. Nothing in the RMSE column announces that a model has degenerated into recommending averages. You only see it by asking what the model does for its hardest users, not its average one — which is a habit worth carrying into any system judged on aggregate error.
The full notebook — the four model generations, the tuning runs and the top-10 evaluation — is on GitHub.