Skip to content

Instantly share code, notes, and snippets.

@binler
Last active December 26, 2024 17:07
Show Gist options
  • Save binler/5d6c006885e97f1ba581cb62071b12fd to your computer and use it in GitHub Desktop.
Save binler/5d6c006885e97f1ba581cb62071b12fd to your computer and use it in GitHub Desktop.
Page reocmmend algorithm
<?php
class PageRecommender
{
private $userLikes; // [userId => [pageId, pageId, ...]]
private $similarUsers;
public function __construct(array $userLikes)
{
$this->userLikes = $userLikes;
$this->similarUsers = [];
}
public function findSimilarUsers($userId)
{
$userPages = $this->userLikes[$userId] ?? [];
$similarities = [];
foreach ($this->userLikes as $otherId => $otherPages) {
if ($otherId !== $userId) {
// Jaccard similarity = (A ∩ B) / (A ∪ B)
$intersection = count(array_intersect($userPages, $otherPages));
$union = count(array_unique(array_merge($userPages, $otherPages)));
$similarities[$otherId] = $union > 0 ? $intersection / $union : 0;
}
}
arsort($similarities);
$this->similarUsers = $similarities;
return $similarities;
}
public function recommendPages($userId, $numRecommendations = 5)
{
$userPages = $this->userLikes[$userId] ?? [];
$this->findSimilarUsers($userId);
$pageScores = [];
$maxSimilarity = max($this->similarUsers);
foreach ($this->similarUsers as $similarUserId => $similarity) {
$normalizedSimilarity = $similarity / $maxSimilarity;
$similarUserPages = $this->userLikes[$similarUserId] ?? [];
foreach ($similarUserPages as $pageId) {
if (!in_array($pageId, $userPages)) {
if (!isset($pageScores[$pageId])) {
$pageScores[$pageId] = 0;
}
$pageScores[$pageId] += $normalizedSimilarity;
}
}
}
arsort($pageScores);
return array_slice($pageScores, 0, $numRecommendations, true);
}
}
// Example usage
$userLikes = [
'user1' => ['page1', 'page2', 'page3', 'page4', 'page5', 'page6', 'page7', 'page8', 'page9', 'page10'],
'user2' => ['page1', 'page2', 'page3', 'page11', 'page12'],
'user3' => ['page2', 'page3', 'page4', 'page13', 'page14'],
'user4' => ['page1', 'page2', 'page3', 'page4', 'page15', 'page16']
];
$recommender = new PageRecommender($userLikes);
$recommendedPages = $recommender->recommendPages('user1', 5);
print_r($recommendedPages);
@binler
Copy link
Author

binler commented Dec 26, 2024

Giải thích chi tiết thuật toán:

  1. Tính độ tương đồng giữa users (Jaccard similarity):
$intersection = count(array_intersect($userPages, $otherPages));
$union = count(array_unique(array_merge($userPages, $otherPages)));
$similarities[$otherId] = $union > 0 ? $intersection / $union : 0;
  • Ví dụ: User1 thích pages [1,2,3], User2 thích pages [2,3,4]
  • Intersection (giao): [2,3] = 2 pages
  • Union (hợp): [1,2,3,4] = 4 pages
  • Similarity = 2/4 = 0.5 (50% similar)
  1. Tính điểm cho mỗi page:
$normalizedSimilarity = $similarity / $maxSimilarity;
$pageScores[$pageId] += $normalizedSimilarity;
  • Chuẩn hóa similarity về thang 0-1
  • Mỗi page sẽ được cộng điểm dựa trên độ tương đồng của user đã like nó
  • Page được like bởi nhiều user tương đồng sẽ có điểm cao hơn
  1. Ví dụ thực tế:
User1: likes [1,2,3]
User2: likes [2,3,4] (similarity 0.5)
User3: likes [3,4,5] (similarity 0.2)
  • Page 4 sẽ được recommend vì:
    • User2 (similarity 0.5) liked it
    • User3 (similarity 0.2) liked it
    • Score = 0.5 + 0.2 = 0.7

Thuật toán này hiệu quả vì:

  • Đề xuất dựa trên hành vi thực tế của users
  • Ưu tiên pages được like bởi users có cùng sở thích
  • Có thể scale tốt với nhiều users và pages

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment