个性推荐②—基于用户协同过滤算法原及优化方案

个性推荐系列目录
个性推荐①——系统总结个性化推荐系统
个性推荐③—基于物品的协同过滤算法及优化方案

个性推荐系统常用的有两种:基于领域的推荐算法和基于内容的过滤算法,前者又分为基于用户的协同推荐算法(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

用图像来表达这一过程:
个性推荐②—基于用户协同过滤算法原及优化方案_第1张图片

三、用户对物品的兴趣度计算

得到用户之间的兴趣相似度后,会给目标用户推荐和他最相似的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个用户感兴趣的物品,这是取自《推荐系统实战》的结果截图
个性推荐②—基于用户协同过滤算法原及优化方案_第2张图片
评价指标

① 准确率和召回率
与K不是线性关系,选择合适的K对获得最高精度是非常重要的。在一定区间内都可以获得较好的准确率和召回率,这里选择80

② 流行度
K越大,流行度越大,因为参考的用户过多,越趋向于推荐热门的产品

③ 覆盖率
K越大,覆盖率越低,是因为K越大,就越容易推荐流行度高的物品,导致长尾挖掘不充分

四、改进方案

1、 降低热门物品的相似度

两个用户对冷门物品采取过同样的行为更能说明他们兴趣的相似度,范例:人人都买新华词典,但并不能说明他们具有相似度,但是都买了数据挖掘,可能就比较相似了

改进后公式如下,该公式惩罚了用户u和用户v共同兴趣列表中热门物品对他们相似度的影响
个性推荐②—基于用户协同过滤算法原及优化方案_第3张图片

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

你可能感兴趣的