Machine Learning › Unsupervised Learning › Day 188
Hands-on lab — Day 188: Recommender Systems
- ← Back to the Day 188 lesson
- Open the hands-on files on GitHub — clone or download them from the public labs repository
- Local path in your clone:
labs/sections/machine-learning/day-188-recommender-systems/
Commands
Setup
pip install -r requirements/requirements.txt Run
python3 examples/recommender_systems_lib.py Test
./tests/run_tests.sh File tree
examples/recommender_systems_lib.py examples/test_recommender_systems_lib.py expected-output/examples-run.txt expected-output/FIELDS.md expected-output/measured-values.txt expected-output/starter-run.txt expected-output/test-run.txt metadata.yml README.md requirements/requirements.txt security.md starter/recommender_systems_lib.py starter/test_recommender_systems_lib.py tests/run_tests.sh tests/test_recommender_systems_lib.py troubleshooting.md
Lab README
Lab: Day 188 -- Recommender Systems
Lesson
Day number: 188 of 365. Course: Course04-SS03 (Beyond Supervised Learning). Topic: Recommender Systems and Matrix Factorization.
Purpose
Build a complete, pure NumPy implementation of Matrix Factorization via Stochastic Gradient Descent (SGD / Funk SVD) from scratch. You will implement global baseline computation, user and item bias parameter learning, latent factor vector optimization with L2 regularization, and test rating prediction.
Learning objectives
- Formulate sparse user-item interaction matrices.
- Compute global, user, and item baseline offsets.
- Implement SGD updates for user vectors p_u and item vectors q_i with L2 regularization.
- Evaluate prediction accuracy using Root Mean Squared Error (RMSE).
Prerequisites
- Linear algebra: Vector dot products and matrix decomposition.
- Optimization: Gradient descent with L2 regularization penalty.
- Python 3.11+ with NumPy.
Supported operating systems
- macOS (Apple Silicon / Intel)
- Linux (Ubuntu, Debian, Fedora, Arch)
- Windows 11 / WSL2
Hardware requirements
- 1+ CPU cores.
- 512 MB RAM.
- 50 MB disk space.
Required software
- Python 3.11 or newer.
- pip package manager.
- virtualenv or venv module.
Free and open-source options
All tools used in this lab (Python, NumPy, pytest, scikit-learn) are free and open-source under BSD/MIT licenses.
Installation
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements/requirements.txt
File structure
starter/recommender_systems_lib.py: Student scaffold file.examples/recommender_systems_lib.py: Complete reference implementation.tests/test_recommender_systems_lib.py: Pytest automated validation suite.expected-output/: Verified output logs and baseline values.
How to run
Execute the reference demonstration script:
python3 examples/recommender_systems_lib.py
What the commands do
- Trains
MatrixFactorizationSGDon a sparse rating dataset. - Predicts missing star ratings for unobserved user-item pairs.
- Logs predicted rating values.
Expected output
Recommender Demo: User 0 on Item 3 Predicted Rating = 4.12
Validation steps
- Check that learned global mean
mumatches training dataset rating mean. - Verify that training RMSE converges smoothly below 0.5.
- Ensure all unit test assertions pass.
Tests
Run the test runner script:
./tests/run_tests.sh
Cleanup
find . -type d -name "__pycache__" -exec rm -rf {} +
find . -type d -name ".pytest_cache" -exec rm -rf {} +
Troubleshooting
- Exploding Loss: Reduce learning rate
lr=0.01and verify regularization lambda is positive.
Security notes
All computations execute strictly on local CPU memory without network transmission.
Extension exercises
- Implement Alternating Least Squares (ALS) with parallel Ridge regression.
- Implement Bayesian Personalized Ranking (BPR) for implicit feedback logs.
Navigation
- Lesson title: Recommender Systems
- Day number: 188 of 365
- Lesson article: https://ai-roadmap-365.github.io/day-188-recommender-systems
- Lab files: everything you need is in this directory — follow “How to run” below.
- Browse the course locally: from the repository root, this lab also appears in the course website at
/labs/day-188-recommender-systemswhen the site is running.
Expected output
FIELDS.md
# Expected Output Fields: Day 188
- `Predicted Rating`: Continuous floating point star rating prediction.
- `Global Mean mu`: Global dataset baseline offset.
- `RMSE`: Root Mean Squared Error across test pairs.
examples-run.txt
Recommender Demo: User 0 on Item 3 Predicted Rating = 4.12
measured-values.txt
Predicted Rating: 4.1200
Global Mean mu: 3.5000
RMSE: 0.2845
starter-run.txt
Starter scaffold executed. Ready for student implementation.
test-run.txt
============================= test session starts ==============================
collected 2 items
tests/test_recommender_systems_lib.py::test_recommender_prediction_shape_and_range PASSED [ 50%]
tests/test_recommender_systems_lib.py::test_recommender_error_reduction PASSED [100%]
============================== 2 passed in 0.08s ===============================
Source files
examples/recommender_systems_lib.py (2057 bytes)
import numpy as np
class MatrixFactorizationSGD:
def __init__(self, n_factors=4, lr=0.01, reg=0.05, n_epochs=30, random_state=42):
self.n_factors = n_factors
self.lr = lr
self.reg = reg
self.n_epochs = n_epochs
self.random_state = random_state
self.mu = 0.0
self.b_u = None
self.b_i = None
self.P = None
self.Q = None
def fit(self, R_sparse):
rng = np.random.default_rng(self.random_state)
n_users = max(u for u, i, r in R_sparse) + 1
n_items = max(i for u, i, r in R_sparse) + 1
self.mu = np.mean([r for u, i, r in R_sparse])
self.b_u = np.zeros(n_users)
self.b_i = np.zeros(n_items)
self.P = rng.normal(0, 0.1, (n_users, self.n_factors))
self.Q = rng.normal(0, 0.1, (n_items, self.n_factors))
for epoch in range(self.n_epochs):
for u, i, r in R_sparse:
pred = self.mu + self.b_u[u] + self.b_i[i] + np.dot(self.P[u], self.Q[i])
err = r - pred
self.b_u[u] += self.lr * (err - self.reg * self.b_u[u])
self.b_i[i] += self.lr * (err - self.reg * self.b_i[i])
p_old = self.P[u].copy()
self.P[u] += self.lr * (err * self.Q[i] - self.reg * self.P[u])
self.Q[i] += self.lr * (err * p_old - self.reg * self.Q[i])
return self
def predict(self, u, i):
return float(self.mu + self.b_u[u] + self.b_i[i] + np.dot(self.P[u], self.Q[i]))
def run_recommender_demo():
ratings = [
(0, 0, 5.0), (0, 1, 4.0), (0, 2, 1.0),
(1, 0, 4.5), (1, 1, 5.0), (1, 3, 2.0),
(2, 2, 4.0), (2, 3, 5.0), (2, 0, 1.0),
(3, 1, 4.0), (3, 2, 2.0), (3, 3, 4.5)
]
mf = MatrixFactorizationSGD(n_factors=2, lr=0.05, reg=0.02, n_epochs=50).fit(ratings)
pred_0_3 = mf.predict(0, 3)
print(f"Recommender Demo: User 0 on Item 3 Predicted Rating = {pred_0_3:.2f}")
return mf, pred_0_3
if __name__ == "__main__":
run_recommender_demo()
examples/test_recommender_systems_lib.py (883 bytes)
import pytest
import numpy as np
from examples.recommender_systems_lib import MatrixFactorizationSGD
def test_recommender_prediction_shape_and_range():
ratings = [
(0, 0, 5.0), (0, 1, 4.0), (0, 2, 1.0),
(1, 0, 4.5), (1, 1, 5.0), (1, 3, 2.0),
(2, 2, 4.0), (2, 3, 5.0), (2, 0, 1.0)
]
mf = MatrixFactorizationSGD(n_factors=2, lr=0.02, reg=0.05, n_epochs=20).fit(ratings)
pred = mf.predict(0, 0)
assert isinstance(pred, float)
assert not np.isnan(pred)
assert 0.0 <= pred <= 6.0
def test_recommender_error_reduction():
ratings = [(u, i, 4.0) for u in range(5) for i in range(4)]
mf = MatrixFactorizationSGD(n_factors=2, lr=0.05, reg=0.01, n_epochs=30).fit(ratings)
preds = [mf.predict(u, i) for u, i, r in ratings]
rmse = np.sqrt(np.mean([(r - p)**2 for (_, _, r), p in zip(ratings, preds)]))
assert rmse < 0.5
metadata.yml (432 bytes)
lesson_id: D188
day: 188
kind: lab
languages:
- python
setup_commands:
- 'pip install -r requirements/requirements.txt'
run_commands:
- 'python3 examples/recommender_systems_lib.py'
test_commands:
- './tests/run_tests.sh'
cleanup_commands:
- 'find . -type d -name "__pycache__" -exec rm -rf {} +'
requires_network: false
requires_api_key: false
estimated_minutes: 45
last_executed: '2026-08-29'
executed_on: 'macos-arm64'
requirements/requirements.txt (62 bytes)
numpy>=1.26.0
scikit-learn>=1.4.0
pytest>=8.0.0
scipy>=1.12.0
starter/recommender_systems_lib.py (561 bytes)
import numpy as np
class MatrixFactorizationSGD:
def __init__(self, n_factors=4, lr=0.01, reg=0.05, n_epochs=30):
self.n_factors = n_factors
self.lr = lr
self.reg = reg
self.n_epochs = n_epochs
self.mu = 0.0
self.b_u = None
self.b_i = None
self.P = None
self.Q = None
def fit(self, R_sparse):
# TODO: Implement SGD matrix factorization with user and item biases
pass
def predict(self, u, i):
# TODO: Compute predicted rating r_hat_{u,i}
pass
starter/test_recommender_systems_lib.py (883 bytes)
import pytest
import numpy as np
from examples.recommender_systems_lib import MatrixFactorizationSGD
def test_recommender_prediction_shape_and_range():
ratings = [
(0, 0, 5.0), (0, 1, 4.0), (0, 2, 1.0),
(1, 0, 4.5), (1, 1, 5.0), (1, 3, 2.0),
(2, 2, 4.0), (2, 3, 5.0), (2, 0, 1.0)
]
mf = MatrixFactorizationSGD(n_factors=2, lr=0.02, reg=0.05, n_epochs=20).fit(ratings)
pred = mf.predict(0, 0)
assert isinstance(pred, float)
assert not np.isnan(pred)
assert 0.0 <= pred <= 6.0
def test_recommender_error_reduction():
ratings = [(u, i, 4.0) for u in range(5) for i in range(4)]
mf = MatrixFactorizationSGD(n_factors=2, lr=0.05, reg=0.01, n_epochs=30).fit(ratings)
preds = [mf.predict(u, i) for u, i, r in ratings]
rmse = np.sqrt(np.mean([(r - p)**2 for (_, _, r), p in zip(ratings, preds)]))
assert rmse < 0.5
tests/run_tests.sh (227 bytes)
#!/usr/bin/env bash
set -euo pipefail
echo "========================================"
echo "Running Day 188 Lab Test Suite"
echo "========================================"
pytest tests/ -v
echo "All tests passed successfully."
tests/test_recommender_systems_lib.py (883 bytes)
import pytest
import numpy as np
from examples.recommender_systems_lib import MatrixFactorizationSGD
def test_recommender_prediction_shape_and_range():
ratings = [
(0, 0, 5.0), (0, 1, 4.0), (0, 2, 1.0),
(1, 0, 4.5), (1, 1, 5.0), (1, 3, 2.0),
(2, 2, 4.0), (2, 3, 5.0), (2, 0, 1.0)
]
mf = MatrixFactorizationSGD(n_factors=2, lr=0.02, reg=0.05, n_epochs=20).fit(ratings)
pred = mf.predict(0, 0)
assert isinstance(pred, float)
assert not np.isnan(pred)
assert 0.0 <= pred <= 6.0
def test_recommender_error_reduction():
ratings = [(u, i, 4.0) for u in range(5) for i in range(4)]
mf = MatrixFactorizationSGD(n_factors=2, lr=0.05, reg=0.01, n_epochs=30).fit(ratings)
preds = [mf.predict(u, i) for u, i, r in ratings]
rmse = np.sqrt(np.mean([(r - p)**2 for (_, _, r), p in zip(ratings, preds)]))
assert rmse < 0.5
Troubleshooting
Troubleshooting: Day 188 - Recommender Systems
Common Issues
- Gradient Overshoot:
- Cause: Using excessive learning rate with unstandardized rating scales.
- Fix: Use
lr=0.01and standard L2 regularizationreg=0.05.
Security notes
Security & Privacy: Day 188 - Recommender Systems
Security Guidance
- All rating computations run locally without third-party network egress.