上一篇博客我简单讲了一下基于用户的协同过滤算法,这里我们一起来学习一下另一种:基于物品的协同过滤算法。基于物品的协同过滤算法是目前业界应用最多的算法,亚马逊、Netflix、Hulu、YouTube等很多平台都采用该算法作为其基础推荐算法。
-
原理
基于物品的协同过滤算法给用户推荐那些和他们之前喜欢的物品相似的物品。但是它并不是利用物品的内容属性计算物品之间的相似度,而是通过分析用户的行为记录计算物品之间的相似度,比如说用户之前买过《数据挖掘导论》,该算法会根据此行为给你推荐《机器学习》,但是 算法并不利用物品的内容属性计算物品之间的相似度,它主要通过分析用户的行为记录计算物品之间的相似度。 -
流程
1. 计算物品之间的相似度;
2. 根据物品的相似度和用户的历史行为给用户生成推荐列表 -
物品相似度计算
余弦相似度公式:
其中 , 分别表示对物品 , 喜欢的用户数, 为同时喜欢 和 的人数。我们这里还是使用漫威英雄举例:假设目前共有5个用户: 、 、 、 、 ;共有5个漫威英雄人物:死侍、钢铁侠、美国队长、黑豹、蜘蛛侠。用户与人物之间的爱好程度如下图所示:
用户 | 喜爱英雄人物 |
---|---|
A | 死侍、钢铁侠、美国队长 |
B | 钢铁侠、黑豹、蜘蛛侠 |
C | 黑豹、美国队长 |
D | 钢铁侠、黑豹、美国队长 |
E | 死侍、美国队长 |
首先还是处理数据,请参考推荐系统实践(一)----基于用户的协同过滤算法(UserCF),这里就不再仔细讲了。
网络上很多帖子都建立了用户-物品倒排列表,但是个人绝的不是必须的,如果有大佬帮忙提出建立列表的原因,请不吝赐教。我这里直接创建系数矩阵。对于每个用户的喜爱人物集合,我们将里面的人物两两加一,得到一个矩阵。最终将这些矩阵相加得到稀疏
矩阵。其中
记录了同时爱好
和
的用户数。(假设下文的表格为矩阵)
用户A:
死侍 | 钢铁侠 | 美国队长 | |
---|---|---|---|
死侍 | 1 | 1 | |
钢铁侠 | 1 | 1 | |
美国队长 | 1 | 1 |
用户B:
钢铁侠 | 黑豹 | 蜘蛛侠 | |
---|---|---|---|
钢铁侠 | 1 | 1 | |
黑豹 | 1 | 1 | |
蜘蛛侠 | 1 | 1 |
用户C:
黑豹 | 美国队长 | |
---|---|---|
黑豹 | 1 | |
美国队长 | 1 |
用户D:
钢铁侠 | 黑豹 | 美国队长 | |
---|---|---|---|
钢铁侠 | 1 | 1 | |
黑豹 | 1 | 1 | |
美国队长 | 1 | 1 |
用户E:
死侍 | 美国队长 | |
---|---|---|
死侍 | 1 | |
美国队长 | 1 |
我们将上面五个矩阵加起来,得到稀疏 矩阵:
死侍 | 钢铁侠 | 美国队长 | 黑豹 | 蜘蛛侠 | |
---|---|---|---|---|---|
死侍 | 1 | 2 | |||
钢铁侠 | 1 | 2 | 2 | 1 | |
美国队长 | 2 | 2 | 2 | ||
黑豹 | 2 | 2 | 1 | ||
蜘蛛侠 | 1 | 1 |
建立好稀疏矩阵之后, 记录了同时爱好 和 的用户数,这样我们就可以带入上面的公式得到物品之间的相似度矩阵W
实现该功能的python方法:
def item_similarity(userSet):
C = dict()
N = dict()
for u, items in userSet.items():
for i in items:
N.setdefault(i, 0)
N[i] += 1
for j in items:
if i == j:
continue
C.setdefault(i, {})
C[i].setdefault(j, 0)
C[i][j] += 1
print("稀疏矩阵: ", C)
W = dict()
for i,related_items in C.items():
for j, cij in related_items.items():
W.setdefault(i, {})
W[i].setdefault(j, 0)
W[i][j] = cij / math.sqrt(N[i] * N[j])
print("物品相似度: ", W)
return W
结果为:
稀疏矩阵: {'钢铁侠': {'死侍': 1, '美国队长': 2, '黑豹': 2, '蜘蛛侠': 1}, '死侍': {'钢铁侠': 1, '美国队长': 2}, '美国队长': {'钢铁侠': 2, '死侍': 2, '黑豹': 2}, '黑豹': {'钢铁侠': 2, '蜘蛛侠': 1, '美国队长': 2}, '蜘蛛侠': {'钢铁侠': 1, '黑豹': 1}}
物品相似度: {'钢铁侠': {'死侍': 0.4082482904638631, '美国队长': 0.5773502691896258, '黑豹': 0.6666666666666666, '蜘蛛侠': 0.5773502691896258}, '死侍': {'钢铁侠': 0.4082482904638631, '美国队长': 0.7071067811865475}, '美国队长': {'钢铁侠': 0.5773502691896258, '死侍': 0.7071067811865475, '黑豹': 0.5773502691896258}, '黑豹': {'钢铁侠': 0.6666666666666666, '蜘蛛侠': 0.5773502691896258, '美国队长': 0.5773502691896258}, '蜘蛛侠': {'钢铁侠': 0.5773502691896258, '黑豹': 0.5773502691896258}}
人物相似度矩阵为:
死侍 | 钢铁侠 | 美国队长 | 黑豹 | 蜘蛛侠 | |
---|---|---|---|---|---|
死侍 | |||||
钢铁侠 | |||||
美国队长 | |||||
黑豹 | |||||
蜘蛛侠 |
同样相似度也可以想推荐系统实践(一)----基于用户的协同过滤算法(UserCF)中一样改进,这里就不再阐述一遍。
- 推荐
通过如下公式计算用户 对一个物品 的兴趣:
其中 表示用户 喜欢的物品集合, 表示和物品 最相似的 个物品集合, 表示物品 和物品 的相似度, 表示用户 对物品 的兴趣, 是用户喜欢的某个物品,所以我们默认 。
def recommend(user, train, W, K):
pi = 1
rank = dict()
interacted_items = train[user]
for item in interacted_items:
print(">>>>>>>>", item)
related_item = []
for user, score in W[item].items():
related_item.append((user, score))
for j, v in sorted(related_item, key=itemgetter(1), reverse=True)[0:K]:
print(j, v)
if j in interacted_items:
continue
if j not in rank.keys():
rank[j]=0
rank[j] += pi * v
print("推荐人物: ", rank)
return rank
这里我们取用户为 , ,即为用户A喜欢的每个人物推荐两个相关度比较高的人物,结果为:
>>>>>>>> 钢铁侠
黑豹 0.6666666666666666
美国队长 0.5773502691896258
>>>>>>>> 死侍
美国队长 0.7071067811865475
钢铁侠 0.4082482904638631
>>>>>>>> 美国队长
死侍 0.7071067811865475
钢铁侠 0.5773502691896258
推荐人物: {'黑豹': 0.6666666666666666}
从上面可以看出,和钢铁侠比较相似的人物为黑豹、美国队长,和死侍比较相似的人物为美国队长、钢铁侠 ,和美国队长相似的两个人物为死侍、钢铁侠 。即推荐出来的人物为黑豹、美国队长、钢铁侠、死侍,但是美国队长、死侍、钢铁侠本来就在用户
喜爱的人物中,所以不用推荐,那么最终推荐的人物就为黑豹了。根据
算法,用户
对黑豹的喜爱程度为: