Step 1: A rating baseline
Lumen wants to predict how a viewer would rate a title they have not seen, then use those predictions to choose what to put in front of them. Before any clever model, find the number a trivial model scores, so you know what "good" has to beat.
The data is already split: train.csv is what you learn from, test.csv is held out. Each row is a
(user, item, rating) on a 1-to-5 scale.
Write two functions in recsys.py:
rmse(pred, actual): root mean squared error between two equal-length arrays. This is how every model in the lab is scored.fit_bias(train, nu, ni): the baseline. Some viewers rate high, some low; some titles are loved, some not. Capture that with three numbers per prediction: the global meanmu, a per-user offsetbu, and a per-item offsetbi. Compute them in that order:mufirst, thenbu[u]as the mean ofrating - muover each user's ratings, thenbi[i]as the mean ofrating - mu - bu[u]over each item's ratings. Return(mu, bu, bi)withbulengthnuandbilengthni; ids never seen stay 0.
predict_bias(model, pairs) is given. Run to see the baseline beat "predict the global mean for everyone".
recsys.py, the file you edit87 lines
"""Lumen streaming: a rating baseline, collaborative filtering, matrix factorization,
and the offline metrics that decide which recommender you would actually ship."""
import csv
import numpy as np
def load(path):
"""Read a ratings CSV into a list of (user, item, rating) triples."""
out = []
with open(path) as f:
for row in csv.DictReader(f):
out.append((int(row["user"]), int(row["item"]), float(row["rating"])))
return out
def dims(train):
"""(n_users, n_items) large enough to index every id in train."""
return max(u for u, _, _ in train) + 1, max(i for _, i, _ in train) + 1
def predict_bias(model, pairs):
"""Bias-model rating for each (user, item): the global mean plus the two offsets."""
mu, bu, bi = model
return np.array([mu + bu[u] + bi[i] for u, i in pairs])
def rmse(pred, actual):
"""Root mean squared error between two equal-length arrays of ratings."""
# TODO (Step 1): root mean squared error between two equal-length arrays.
raise NotImplementedError("Step 1: write rmse()")
def fit_bias(train, nu, ni):
"""Global mean, then a per-user offset, then a per-item offset on what is left.
Returns (mu, bu, bi) with bu length nu and bi length ni (unseen ids stay 0)."""
# TODO (Step 1): mu, then per-user offset over (rating-mu), then per-item offset over (rating-mu-bu[u]); return (mu, bu, bi).
raise NotImplementedError("Step 1: write fit_bias()")
def item_similarity(train, model, nu, ni):
"""Cosine similarity between items over the bias residuals users left on them.
Returns an (ni, ni) matrix with a zero diagonal (an item is no neighbour of itself)."""
raise NotImplementedError("item_similarity() arrives in Step 2")
def predict_cf(train, model, S, pairs, k=20):
"""Predict a rating as the bias estimate plus a similarity-weighted average of the
residuals the user left on their k most similar rated items."""
raise NotImplementedError("predict_cf() arrives in Step 2")
def recommend(scores, seen, n=10):
"""The n highest-scoring item ids the user has not already rated, best first."""
raise NotImplementedError("recommend() arrives in Step 3")
def recall_at_k(recommended, relevant):
"""Share of the relevant items that appear in the recommended list."""
raise NotImplementedError("recall_at_k() arrives in Step 3")
def precision_at_k(recommended, relevant):
"""Share of the recommended items that are relevant."""
raise NotImplementedError("precision_at_k() arrives in Step 3")
def fit_mf(train, nu, ni, k=8, epochs=40, lr=0.02, reg=0.05, seed=0):
"""Biased matrix factorization by SGD: r ~= mu + bu[u] + bi[i] + P[u].Q[i].
Deterministic given seed. Returns (mu, bu, bi, P, Q)."""
raise NotImplementedError("fit_mf() arrives in Step 4")
def predict_mf(model, pairs):
"""Rating for each (user, item) from a fitted factorization model."""
raise NotImplementedError("predict_mf() arrives in Step 4")
def popularity(train, ni):
"""How many users rated each item: the popularity score, ignoring the ratings."""
raise NotImplementedError("popularity() arrives in Step 5")
def ranking_recall(score_of, test, seen_by_user, n=10, min_rating=4.0):
"""Mean recall@n over the held-out items a user actually liked (rating >= min_rating).
score_of(u) returns a score for every item; already-rated items are excluded first."""
raise NotImplementedError("ranking_recall() arrives in Step 5")catalog.csvtest.csvtrain.csvtry_it.py