App: recommendation engine end-to-end

Xây engine gợi ý hoàn chỉnh: content-based, collaborative filtering user và item, matrix factorization, xử lý cold start, đo precision và đa dạng.
Chuyên giaThuật toán ~120 phút

Giới thiệu

Bài này xây máy gợi ý phim và sản phẩm. Người cũ gợi theo gu, người mới gợi theo top phổ biến.

Kiến thức cần nhớ

Content-based theo metadata

  • Vector hóa thể loại và mô tả bằng TF-IDF.
  • Profile user là trung bình vector các item đã thích.
  • Gợi ý bằng cosine giữa profile và item chưa xem.
  • Ví dụ đời thường: thích phim hành động thì gợi thêm phim hành động.

Collaborative filtering theo đám đông

  • User-based: người giống bạn thích gì thì gợi nấy.
  • Item-based: ai thích món này cũng thích món kia.
  • Cần đủ rating chung mới tin, ít quá thì rất nhiễu.
  • Ví dụ đời thường: bạn cùng gu khen hay thì bạn cũng thấy hay.

Matrix factorization và cold start

  • Phân rã ma trận rating thành 2 ma trận latent user và item.
  • Dự đoán bằng tích vô hướng 2 vector latent.
  • User mới thì gợi phổ biến cộng theo thể loại đăng ký.
  • Item mới chỉ có metadata thì đi nhánh content-based.
Mô hìnhCần gìMạnh khi nào
Content-basedMetadata itemItem mới, user ít lịch sử
CFRating chungUser cũ đông
FactorizationNhiều ratingGu ẩn phức tạp

Ví dụ

  • Input: user mê hành động, hỏi top-10. Output: trên 60% phim hành động, không chứa phim đã xem.
  • Giải thích: cosine đẩy phim cùng thể loại lên đầu, bộ lọc bỏ phim đã xem.
  • Input: user mới tinh vừa đăng ký. Output: danh sách phổ biến theo thể loại đã chọn.
  • Giải thích: chưa có lịch sử nên đi nhánh cold start.

💻 Bài tập

Ngôn ngữ: Python 3. Dùng code ngày 58, 59, 91. Dữ liệu MovieLens 1M (hoặc 100K). Nộp vào day-131-recsys/.

Bài 1: Pipeline dữ liệu

  1. Nạp rating, phim, người dùng. Kiểm tra dữ liệu: rating ngoài 1-5, id trùng, phim thiếu thể loại.
  2. Chia theo thời gian: mỗi user, 80% rating cũ là train, 20% mới là test.
  3. Lưu dữ liệu đã xử lý ra Parquet. Pipeline chạy lại cho cùng kết quả.

Bài 2: Ba mô hình và bộ điều phối

Mô hìnhDùng khi
PopularityModelUser mới, 0 rating
ContentModel (ngày 58)User có 1-9 rating, hoặc phim mới chưa ai chấm
MFModel (ngày 91)User có từ 10 rating
class Recommender:
    def recommend(self, user_id: int, n: int = 10, exclude_seen: bool = True) -> list[tuple[int, float, str]]:
        """Trả (movie_id, score, lý_do). Lý do ví dụ: "Vì bạn thích Toy Story" hoặc "Phổ biến tuần này"."""

Ràng buộc: không gợi phim user đã xem. Luôn trả đủ n phim (bù bằng phổ biến nếu thiếu).

Bài 3: Đánh giá và API (nâng cao)

  1. Tính cho từng nhóm user (0, 1-9, 10+ rating): precision@10, recall@10, NDCG@10, coverage (tỉ lệ phim từng được gợi ý), độ đa dạng thể loại.
  2. So bộ điều phối với từng mô hình đơn lẻ.
  3. Viết API GET /recommend?user_id=..&n=.. bằng FastAPI. Độ trễ p99 dưới 50 ms (tính trước vector, dùng numpy cho tích vô hướng).
  4. README.md: sơ đồ pipeline, cách chạy, bảng kết quả.

✅ Tiêu chí hoàn thành

  • Pipeline tất định, chạy lại cho cùng file Parquet.
  • User mới vẫn nhận đủ 10 gợi ý có lý do.
  • Bảng metric theo nhóm user có số thật.
  • API chạy, có số đo p99.

❓ Câu hỏi ôn tập

  • Content-based tính điểm gợi ý thế nào?
  • CF user-based khác item-based ở điểm gì?
  • Factorization học gu ẩn bằng cách nào?
  • Cold start xử lý user và item mới ra sao?

🌕 Bạn đã hoàn thành ngày 131. Làm hết bài tập phía trên rồi sang ngày tiếp theo.

Bớt paste mù, hiểu sâu từng dòng mình viết.

180 Days Challenge. 180 ngày cai nghiện vibe code.