基于物品的协同过滤
上一节介绍了基于用户的协同过滤,思想是找到跟自己兴趣最相似的 K 个用户,根据他们的兴趣找到目标用户感兴趣的物品。而基于物品的协同过滤其实跟基于用户的协同过滤非常相似。
基于物品的协同过滤的思想是:根据用户之前喜欢的物品,给他们推荐与用户喜欢过的物品相似度高的新的物品。
基于物品的协同过滤算法分为两步:
(1)计算物品之间的相似度。
(2)根据物品的相似度和用户历史行为给用户生成推荐列表。
计算物品之间的相似度
假设N(i) 是喜欢物品 i 的用户数,N(j) 是喜欢物品 j 的用户数。该算法认为,物品 A 和 物品B 具有很大的相似度是因为喜欢物品A 的用户大多也喜欢物品 B 。可以用下面的公式和代码实现:
def ItemSimilarity(train):
#计算 C[i][j]
C = dict()
N = dict()
for u,items in train.items():
for i in items:
N[i] += 1
for j in items:
if i == j :continue
C[i][j] += 1
#计算 W[i][j]
W = dict()
for i,related_items in C.items():
for j,cij in related_items.items():
W[i][j] = cij / math.sqrt(N[i] * N[j])
return W
该算法的图形解释如下,图中最左边是输入的用户行为记录,每一行代表一个用户感兴趣的物品集合。然后,对于每个物品集合,我们将里面的物品两两加 1 ,得到一个矩阵。最后将这些矩阵相加得到 C 矩阵。其中 C[i][j] 记录了同时喜欢物品i 和物品 j 的用户数。最后将C 矩阵归一化可以得到物品之间的余弦相似度矩阵 W 。
计算物品之间的相似度 -- 算法优化(用户活跃度的影响)
从前面的计算方法可以看到,在协同过滤中两个物品产生相似度是因为它们共同出现在很多用户的兴趣列表中。换句话说,每个用户的兴趣列表都对物品的相似度产生贡献。活跃用户对物品相似度的贡献应该小于不活跃的用户。
假设有这么一个用户,他是搞批发的,假如他一次性批发几万件物品。其实这些物品相关度都不大且是随机的,因为他虽然活跃,但是并不是出于个人兴趣的行为。所以他购买的物品两两之间的相似度贡献应该远远小于一个只买了几件物品的普通用户。
所以修正之后的相似度公式应该加入用户活跃度的惩罚项,更正后公式和代码如下:
def ItemSimilarity(train):
#计算 C[i][j]
C = dict()
N = dict()
for u,items in train.items():
for i in items:
N[i] += 1
for j in items:
if i == j:continue
#加入活跃度惩罚项 1 / math.log(1 + len(items))
C[i][j] += 1 / math.log(1 + len(items) * 1.0)
#计算 W[i][j]
W = dict()
for i,related_items in C.items():
for j,cij in related_items.items():
W[i][j] = cij / math.sqrt(N[i] * N[j])
return W
如果进一步优化,可以考虑对相似度矩阵 W 归一化处理。
得到物品相似度之后,我们开始第二步,给出推荐列表
在得到物品之间相似度后,ItemCF 算法通过下列公式计算用户 u 对一个物品 j 的兴趣:
这里 N(u) 是用户喜欢的物品集合,S(j,K) 是和物品 j 最相似的 K 个物品的集合,wji 是物品 j 和物品 i 的相似度,rui 的是用户u对物品 i 的兴趣(对于隐性反馈数据集,如果用户u 对物品 i 有过行为,即可令 rui = 1)。该公式的含义是,和用户历史上感兴趣越相似的物品,越可能在用户的推荐列表中获得较高的排名。代码计算如下:
def Recommendation(train,user_id,W,K):
rank = dict()
ru = train[user_id]
for i,rui in ru.items():
for j,wji in sorted(W[i].items(),key = itemgetter(1),reverse = True)[0:K]:
if j in ru:continue
rank[j] += rui * wji
return rank
下图是 ItemCF 算法的图形表示:
不同的 K 值对 ItemCF 算法的影响
准确率和召回率:可以看出 ItemCF 推荐结果的精度也是不跟 K 值成正负相关的。
流行度:和 UserCF 不同,参数 K 对 ItemCF 推荐结果流行度的影响也是不完全正相关的。
覆盖率:K 值增加会降低系统的覆盖率。