Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
Feedback comes in two flavors and confusing them is one of the most common beginner mistakes. Explicit feedback is a user deliberately telling you their preference — a 5-star rating, a thumbs-up, an explicit 'not interested.' It's clean and directly interpretable but vanishingly rare: most users never rate anything. Implicit feedback is everything else — clicks, watches, purchases, dwell time, scroll depth — and it's abundant but ambiguous. A click might mean 'I loved this' or 'the thumbnail tricked me and I bounced in two seconds.' A non-click might mean 'not interested' or 'I never scrolled that far.' Almost every real recommender is trained overwhelmingly on implicit signals, which means you must design confidence weighting and negative-sampling strategies around that ambiguity rather than pretending implicit clicks are ratings in disguise. Getting this distinction wrong quietly poisons everything downstream.
The demo builds both an explicit ratings matrix (mostly empty) and an implicit interaction matrix (dense but noisy) from the same underlying users, then measures how much of the catalog each one actually covers.
bounce case: a 2-second dwell time, and confirm confidence() correctly assigns it near the minimum weight versus a 300-second dwell.import random
random.seed(2)
users = [f"u{i}" for i in range(200)]
items = [f"i{i}" for i in range(500)]
# Explicit: users rarely bother to rate (~3% of user-item pairs)
explicit = {}
for u in users:
n_rated = random.choices([0, 1, 2, 3], weights=[70, 20, 8, 2])[0]
for it in random.sample(items, n_rated):
explicit[(u, it)] = random.randint(1, 5)
# Implicit: clicks/plays are far more common but only weakly tied to "liking"
implicit = {}
for u in users:
n_clicks = random.randint(5, 40)
for it in random.sample(items, min(n_clicks, len(items))):
# dwell_seconds is our confidence signal, not a rating
implicit[(u, it)] = random.expovariate(1 / 30) # avg 30s dwell
explicit_coverage = len(explicit) / (len(users) * len(items))
implicit_coverage = len(implicit) / (len(users) * len(items))
print(f"explicit pairs: {len(explicit):5d} coverage={explicit_coverage:.2%}")
print(f"implicit pairs: {len(implicit):5d} coverage={implicit_coverage:.2%}")
# Confidence weighting (Hu/Koren/Volinsky style): more dwell time -> more
# confidence the click was a real positive, not an accidental bounce.
def confidence(dwell_seconds: float, alpha: float = 40.0) -> float:
return 1 + alpha * min(dwell_seconds, 300) / 300
sample = list(implicit.items())[:5]
for (u, it), dwell in sample:
print(f"{u} x {it}: dwell={dwell:5.1f}s confidence={confidence(dwell):.2f}")python3 main.py