类似视频的评分、商品的评分这些为显示反馈;浏览日志、购买日志这些为隐式反馈。
userId、itemId、behaviorType、context(上下文,时间地点等)、behaviorWeight、behaviorContent
UserCF | ItemCF | |
---|---|---|
性能 | 适用于用户较少的场合 | 适用于物品数目明显小于用户数的场合 |
领域 | 时效性较强,个性化兴趣不太明显 | 长尾物品丰富 |
实时性 | 用户有新行为不一定导致推荐结果立即变化 | 用户有新行为一定会导致推荐结果实时变化 |
冷启动 | 在新用户对很少物品产生行为后不能立即进行个性化推荐,因为用户相似度是每隔一段时间离线计算的;新物品上线一段时间后,一旦有用户对物品产生行为就可以将它推给其他人 | 新用户只要对一个物品产生行为就可以给他推荐相关物品;没有办法在不离线更新物品相似度表的情况下将新物品退给用户 |
推荐理由 | 难以提供 | 可以解释 |
def ItemCF_Norm(self):
# 建立物品-物品的共现矩阵
C = dict() # 物品-物品的共现矩阵
N = dict() # 物品被多少个不同用户购买
for user, items in self.train.items():
for i in items.keys():
N.setdefault(i, 0)
N[i] += 1
C.setdefault(i, {
})
for j in items.keys():
if i == j: continue
C[i].setdefault(j, 0)
C[i][j] += 1
#C[i][j] += 1 / math.log(1 + len(items) * 1.0) # IUF
# 计算相似度矩阵
self.W = dict()
for i, related_items in C.items():
self.W.setdefault(i, {
})
for j, cij in related_items.items():
self.W[i][j] = cij / (math.sqrt(N[i] * N[j]))
# 归一化
for item1, dic in self.W.items():
max = sorted(self.W[item1].items(), key=lambda x: x[1], reverse=True)[0][1]
for item2, sim in dic.items():
self.W[item1][item2] = self.W[item1][item2] / max
self.SaveDict('data/itemcf_norm.data', self.W)
return self.W
def Recommend(self, user, K=10, num_recommend=10, num_recent=5):
rank = dict()
watched_item = self.train[user] # 用户user产生过行为的item和评分
recent_item = self.getRecent(user, num_recent) # 看过的并且喜欢(4分以上)的电影按时间排序
for movie, list in recent_item:
for related_movie, w in sorted(self.W[movie].items(), key=lambda x: x[1], reverse=True)[:K]:
if related_movie in watched_item.keys():
continue
rank.setdefault(related_movie, [0, movie])
rank[related_movie][0] += list[0] * w # list[0]是评分 list[1]是时间
return dict(sorted(rank.items(), key=lambda x: x[1], reverse=True)[0:num_recommend])
def Recall(self, N=30):
hit = 0
all = 0
for user_id in self.train.keys():
if user_id in self.test.keys():
tu = self.test[user_id]
rank = self.Recommend(user_id, num_recommend=N)
for item_id, pui in rank.items():
if item_id in tu.keys():
hit += 1
all += len(tu)
return hit / (all * 1.0)
def Precision(self, N=30):
hit = 0
all = 0
for user_id in self.train.keys():
if user_id in self.test.keys():
tu = self.test[user_id]
rank = self.Recommend(user_id, num_recommend=N)
for item_id, pui in rank.items():
if item_id in tu.keys():
hit += 1
all += N
return hit / (all * 1.0)