MySQL中的协同过滤?

20

我正在尝试开发一个网站,根据用户的偏好推荐物品(如书籍)。到目前为止,我已经阅读了O'Reilly的“集体智慧”和其他许多在线文章。然而,它们似乎都只涉及单个推荐实例,例如如果你喜欢书A,那么你可能会喜欢书B。

我想要创建一组“偏好节点”给我的网站上的每个用户。假设一个用户喜欢书A、B和C。那么,当他们添加书D时,我不希望系统仅基于其他用户对书D的经验来推荐其他书籍。我希望系统查找相似的“偏好节点”,并根据此推荐书籍。

这里是4个节点的示例:

User1: 'book A'->'book B'->'book C'
User2: 'book A'->'book B'->'book C'->'book D'
user3: 'book X'->'book Y'->'book C'->'book Z'
user4: 'book W'->'book Q'->'book C'->'book Z'
根据我阅读的材料,推荐系统会向用户1推荐书籍Z,因为有两个人同时推荐Z和喜欢C(即Z比D更重要),尽管具有类似“偏好节点”的用户2更有资格向用户推荐书籍D,因为他们的兴趣模式更相似。您有这方面的任何经验吗?我应该尝试阅读哪些内容或是否存在任何开放源代码系统?
谢谢您的时间!
小改动:我认为last.fm的算法正在做我想做的事情。使用人们的偏好树来更个性化地推荐音乐,而不仅仅是说“你可能会喜欢B,因为你喜欢A”。
1个回答

55

创建一个表并插入测试数据:

CREATE TABLE `ub` (
  `user_id` int(11) NOT NULL,
  `book_id` varchar(10) NOT NULL,
  PRIMARY KEY (`user_id`,`book_id`),
  UNIQUE KEY `book_id` (`book_id`,`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

insert into ub values (1, 'A'), (1, 'B'), (1, 'C');
insert into ub values (2, 'A'), (2, 'B'), (2, 'C'), (2,'D');
insert into ub values (3, 'X'), (3, 'Y'), (3, 'C'), (3,'Z');
insert into ub values (4, 'W'), (4, 'Q'), (4, 'C'), (4,'Z');

按照book_id将测试数据与其自身连接,并创建一个临时表来保存每个user_id以及它与目标user_id有多少本书相同:

create temporary table ub_rank as 
select similar.user_id,count(*) rank
from ub target 
join ub similar on target.book_id= similar.book_id and target.user_id != similar.user_id
where target.user_id = 1
group by similar.user_id;

select * from ub_rank;
+---------+------+
| user_id | rank |
+---------+------+
|       2 |    3 |
|       3 |    1 |
|       4 |    1 |
+---------+------+
3 rows in set (0.00 sec)
我们可以看到user_id 与 user_id 1 有3个共同的,但是user_id 3和user_id 4每个只有1个。 接下来,选择临时表中用户拥有但与目标user_id的书籍不匹配的所有书籍,并按等级排序。注意,相同的书可能出现在不同用户的列表中,因此我们对每本书进行排名求和,以使共同的书籍获得更高的排名。
select similar.book_id, sum(ub_rank.rank) total_rank
from ub_rank
join ub similar on ub_rank.user_id = similar.user_id 
left join ub target on target.user_id = 1 and target.book_id = similar.book_id
where target.book_id is null
group by similar.book_id
order by total_rank desc;

+---------+------------+
| book_id | total_rank |
+---------+------------+
| D       |          3 |
| Z       |          2 |
| X       |          1 |
| Y       |          1 |
| Q       |          1 |
| W       |          1 |
+---------+------------+
6 rows in set (0.00 sec)

书籍Z出现在两个用户的列表中,因此排名高于仅出现在一个用户列表中的X、Y、Q、W。书籍D表现最好,因为它出现在用户ID 2的列表中,该列表与目标用户ID 1有3项共同之处。


1
哇,这是一个非常全面的回答。非常感谢! - soren.qvist
这是一个非常棒的答案,我已经在我的网站上使用了一个修改过的版本,并且它运行得非常好。 - Franco
2
这个在处理大数据集方面表现如何? - Luke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接