个性推荐系列目录:
个性推荐①——系统总结个性化推荐系统
个性推荐③—基于物品的协同过滤算法及优化方案
个性推荐系统常用的有两种:基于领域的推荐算法和基于内容的过滤算法,前者又分为基于用户的协同推荐算法(userCF)和基于物品的协同过滤(itemCF),本篇重点介绍基于用户的协同推荐算法的原理、适用范围及优化方案
① 找到和目标用户相似的用户集合
② 找到这个集合中用户喜欢的,且目标用户没有听过或产生过行为的物品,推荐给目标用户
基于用户历史行为得到用户相似度
以电商为例,如果两人共同购买的物品越多,两人越具有相似度。
以新闻为便,如果两人共同看过的新闻越多,两人越具有相似度
这里的购买,看过,都是用户的历史行为。
而如何量化这种相似度呢?——余弦相似度
给定用户u和用户v,令N(u)表示用户u曾经有过正反馈的物品集合,令N(v)
为用户v曾经有过正反馈的物品集合。W就是两两用户的相似度矩阵
def UserSimilarity(train):
W = dict()
for u in train.keys():
for v in train.keys():
if u == v:
continue
W[u][v] = len(train[u] & train[v])
W[u][v] /= math.sqrt(len(train[u]) * len(train[v]) * 1.0)
return W
如果有N个用户,则要计算N*N次,时间复杂度太高,鉴于很多用户之间并没有对同样的物品产生过行为,分子都是0,因此可以先找到不为0的用户对,再计算相似度
做法:通过建立物品到用户的倒排表,对于每个物品都保存产生过行为的用户,通过扫描这个表,可以获得两两用户之间的共同物品的数量,再除以分母就得到了相似度矩阵
def UserSimilarity(train):
# build inverse table for item_users
item_users = dict()
for u, items in train.items():
for i in items.keys():
if i not in item_users:
item_users[i] = set()
item_users[i].add(u)
#calculate co-rated items between users
C = dict()
N = dict()
for i, users in item_users.items():
for u in users:
N[u] += 1
for v in users:
if u == v:
continue
C[u][v] += 1
#calculate finial similarity matrix W
W = dict()
for u, related_users in C.items():
for v, cuv in related_users.items():
W[u][v] = cuv / math.sqrt(N[u] * N[v])
return W
得到用户之间的兴趣相似度后,会给目标用户推荐和他最相似的K个用户的喜欢的物品
S(u, K)包含和用户u兴趣最接近的K个用户,N(i)是对物品i有过行为的用户集合,wuv
是用户u和用户v的兴趣相似度,rvi代表用户v对物品i的兴趣,因为使用的是单一行为的隐反馈数据,所以所有的rvi=1
def Recommend(user, train, W):
rank = dict()
interacted_items = train[user]
for v, wuv in sorted(W[u].items, key=itemgetter(1), \
reverse=True)[0:K]:
for i, rvi in train[v].items:
if i in interacted_items:
#we should filter items user interacted before
continue
rank[i] += wuv * rvi
return rank
UserCF只有一个重要的参数K,即为每个用户选出K个和他兴趣最相似的用户,然后推荐那K个用户感兴趣的物品,这是取自《推荐系统实战》的结果截图
评价指标
① 准确率和召回率
与K不是线性关系,选择合适的K对获得最高精度是非常重要的。在一定区间内都可以获得较好的准确率和召回率,这里选择80
② 流行度
K越大,流行度越大,因为参考的用户过多,越趋向于推荐热门的产品
③ 覆盖率
K越大,覆盖率越低,是因为K越大,就越容易推荐流行度高的物品,导致长尾挖掘不充分
1、 降低热门物品的相似度
两个用户对冷门物品采取过同样的行为更能说明他们兴趣的相似度,范例:人人都买新华词典,但并不能说明他们具有相似度,但是都买了数据挖掘,可能就比较相似了
改进后公式如下,该公式惩罚了用户u和用户v共同兴趣列表中热门物品对他们相似度的影响
def UserSimilarity(train):
# build inverse table for item_users
item_users = dict()
for u, items in train.items():
for i in items.keys():
if i not in item_users:
item_users[i] = set()
item_users[i].add(u)
#calculate co-rated items between users
C = dict()
N = dict()
for i, users in item_users.items():
for u in users:
N[u] += 1
for v in users:
if u == v:
continue
C[u][v] += 1 / math.log(1 + len(users))
#calculate finial similarity matrix W
W = dict()
for u, related_users in C.items():
for v, cuv in related_users.items():
W[u][v] = cuv / math.sqrt(N[u] * N[v])
return W
上述通过在分母中增加物品的流行度作为惩罚项后,准确率和覆盖率都有提升,但是却未必完全能削弱掉热门物品的影响,尤其是热门物品实在过于热门的情况下。针对这一情况,可以将惩罚做得再重一些
其中α∈[0.5 ,1] 。通过提高α,就可以惩罚热门的j
2、加入时间上下文信息
防止每天的推荐列表都差不多,缺乏新颖性
通常采用方法:
a) 生成推荐列表时假如一定的随机性,比如从推荐前30个中随机挑选20个
b)记录每天给用户的推荐结果,给出现次数过多的物品降低权重
c) 每天使用不同的推荐算法,比如协同过滤,基于内容过滤等
针对userCF:
① 用户相似度:两者对同一物品产生行为的时间间隔越近,相似度越大
用户u和用户v共同喜欢的物品i增加了一个时间衰减因子。用户u和用户
v对物品i产生行为的时间越远,那么这两个用户的兴趣相似度就会越小
def UserSimilarity(train):
# build inverse table for item_users
item_users = dict()
for u, items in train.items():
for i,tui in items.items():
if i not in item_users:
item_users[i] = dict()
item_users[i][u] = tui
#calculate co-rated items between users
C = dict()
N = dict()
for i, users in item_users.items():
for u,tui in users.items():
N[u] += 1
for v,tvi in users.items():
if u == v:
continue
C[u][v] += 1 / (1 + alpha * abs(tui - tvi))
#calculate finial similarity matrix W
W = dict()
for u, related_users in C.items():
for v, cuv in related_users.items():
W[u][v] = cuv / math.sqrt(N[u] * N[v])
return W
② 相似用户的兴趣:相似用户最近喜欢的物品,兴趣度要高于之前喜欢的
def Recommend(user, T, train, W):
rank = dict()
interacted_items = train[user]
for v, wuv in sorted(W[u].items, key=itemgetter(1),
reverse=True)[0:K]:
for i, tvi in train[v].items:
if i in interacted_items:
#we should filter items user interacted before
continue
rank[i] += wuv / (1 + alpha * (T - tvi))
return rank
下一篇将会总结基于物品协同过滤算法,感兴趣的小伙伴可以关注下我喔
本篇内容整理自个性推荐经典之作《推荐系统实战》
链接: https://pan.baidu.com/s/19Hz7hKjsHGTzs-7i2VaBsw 提取码: tpsk