# Content Based Filtering (CBF)
Trong phần này, ta sẽ xét đến một phương án xây dựng hệ thống đề xuất dựa trên sự tương đồng về nội dung của các item. Điều này dựa trên việc trong thực tế, thông thường mỗi user sẽ thích một số chủ đề nhất định, chẳng hạn một số người thích phim hành động, một số khác thích phim hài, một số lại thích phim có thần tượng của họ đóng. Do đó khi đã có phần nào đó dữ liệu các item đã được đánh giá thì chúng ta hoàn toàn có thể xây dựng được một hệ thống đề xuất dựa trên phần nội dung của item.
Một hệ thống dựa trên CBF sẽ bao gồm ba thành phần chính:
- Content Analyzer: thành phần này sẽ đóng vai trò xây dựng "profile" cho mỗi item. Ở đây, khái niệm "profile" có thể hiểu như là một vector biểu diễn cho item đó. Tất nhiên tuỳ thuộc vào item mà ta có thể có cách biểu diễn khác.
- User Profile: Đây là thành phần chính của CBF, ở đây tuỳ thuộc vào cách chúng ta xây dựng mà User Profile có thể đơn giản chỉ là danh sách các item mà user đó đã đánh giá hoặc có thể phức tạp đến mức là 1 mạng Neural nhiều lớp.
- Item Retriever: Thành phần này sẽ trích xuất các item bằng cách tiến hành so sánh giữa user profile và item profile.
Để xây dựng item profile cho mỗi item cụ thể ở đây là mỗi bộ phim, ta sẽ tiến hành thu thập thông tin về các bộ phim: giới thiệu sơ lược, năm sản xuất, các diễn viên chính, thể loại phim, đạo diễn, biên kịch, thể loại, ngôn ngữ...Để làm được điều này thì ta có thể thực hiện bằng 2 cách:
- Đầu tiên ta có thể sử dụng các thư viện hỗ trợ cào thông tin như Beautiful Soup, Selenium hay các công cụ có hỗ trợ giao diện người dùng như web scraping để lấy các thông tin trên từ trang web chính thức của bộ phim hoặc một số trang web khác như imdb.com, douban.cn, netflix.com... Tuy nhiên các trang web này thông thường có các công cụ để giới hạn số lượng request đến server hoặc sử dụng các công cụ bảo vệ tránh truy câp từ bots như Cloudflare, do đó việc thu thập như thế này không phải lúc nào cũng làm được.
- Sử dụng API do chính các trang web trên cung cấp hoặc sử dụng thông qua bên thứ ba, cách này sẽ hiêu quả hơn so với cách trên vì ta chỉ cần sử dụng các request có sẵn theo tài liệu được cung cấp.

Chẳng hạn, trong hình ảnh trên là thông tin về Harry Potter và Hòn đá phù thuỷ, ta sẽ lấy toàn bộ các thông tin về thể loại, phần giới thiệu qua về nội dung tác phẩm, thông tin về đạo diễn, biên kịch và các diễn viên chính.
Tiếp theo, sau khi đã thu thập được các thông tin liên quan đến các item thì ta sẽ tìm cách biểu diễn phù hợp cho các thông tin này. Để đơn giản thì ta sẽ biểu diễn thông qua các tag(thẻ) mà ta trích xuất ra đươc từ các nội dung mà ta đã lấy được ở phần trên, ví dụ, từ thông tin của bộ phim Harry Potter và Hòn đá phù thuỷ, ta có thể xây dựng môt vector như sau:
| Adventure | Family | Fantasy | magical | orphaned | Vietnam |
| -------- | -------- | -------- | --------| -------| -------- |
| 1 | 1 | 1 | 1 | 1| 0|
Ở đây ta chỉ đơn giản đếm số lần xuất hiện của các tag trong phần nội dung ta lấy được của item. Một vấn đề sẽ nảy sinh đó là sẽ có một số tag rất phổ biến mà hầu như item nào cũng có, khi đó ở phần sau khi ta so sánh độ tương đồng thì nó sẽ bị ảnh hưởng phần lớn bởi các tag này, do đó ta cần có một công cụ để giảm bớt ảnh hưởng của điều này. Khi đó ta có thể sử dụng ***tf-idf***:
$$ tfidf(d_i, t_j) = count(d_i, t_j) * log (\frac {N} {D_{t_j}})$$
Trong đó:
- $d_i$ là nội dung trích xuất được của item thứ $i$.
- $t_j$ là nội dung tag $j$.
- $count(d_i, t_j)$ là số lần xuất hiện tag $t_j$ trong $d_i$.
- $D_{t_j}$ là số lượng item chứa tag $t_j$.
- $N$ là số lượng item.
Bây giờ ta có thể thấy khi gần như mọi item $i$ đều chứa tag $t_j$ thì giá trị ***tf-idf*** sẽ gần bằng 0, như vậy lúc này ta sẽ loại bỏ được ảnh hưởng của những thành phần phổ biến.
Sau khi đã xây dưng được các vector item profile, lúc này ta sẽ đưa bài toán về một bài toán classification / regression thông thường. Gọi $score(i, j)$ là dự đoán đánh giá của user $i$ dành cho item $j$. Ta thấy rằng nếu ta xét một user $i$ cụ thể nào đó, lúc này ta sẽ thấy rằng bài toán dự đoán rating tương đương với việc xây dựng một mô hình cho user $i$ với phần dữ liệu input đầu vào là các item vector và đánh giá của user này cho các item đó. Ở đây, trong quá trình testing thì ta sẽ xét nhiều mô hình khác nhau.
Tuy nhiên ở đây ta sẽ gặp phải một vấn đề lớn, đó là số lượng rating trung bình của 1 user thông thường sẽ nhỏ so với số lượng item, trong khi đó kích thước các item profile thông thường rất lớn (số chiều từ vài ngàn đến vài chục ngàn). Điều này dẫn đến việc mô hình sẽ khó hội tụ. Một vấn đề khác là nhìn chung các item profile sẽ có phần lớn các giá trị bằng 0. Do đó để có thể đạt hiệu quả trong quá trình training mô hình, ta sẽ tiến hành giảm số chiều dữ liệu, việc này có thể được thực hiện bằng cách sử dụng *PCA*.