用户行为在个性化推荐系统种一般分为两种,显性反馈和隐形反馈。显示反馈包含明确的用户喜好行为,如点赞和讨厌等。隐形反馈是不明确的,如用户浏览记录等。
大部分用户只关注到热门物品,非热门物品无人问津。且用户越活跃越关心冷门物品。
仅仅根据用户行为数据设计的推荐算法一般称为协同过滤算法。可以分为基于邻域的方法,隐语义方法,基于图的随机游走算法等。
R ( u ) R(u) R(u)表示对用户u推荐的N个物品。而 T ( u ) T(u) T(u)表示u确实喜欢的物品。
准确率(precision)反映了,预测的东西中真实被喜欢的占的比例。
召回率(recall)反映了,喜欢的东西被准确预测的比例。
基本思想是,当用户A需要个性化推荐时,可以找到与该用户兴趣接近的用户,然后把那些用户喜欢的但是A用户没有听说过的物品推荐给A。
主要包括两个步骤,1.找到相似兴趣的用户,2.找到这个集合的用户喜欢的,且目标用户没有听说过的物品推荐给目标用户。
在具体的代码实现上,一般采用首先建立物品倒排表的方法。假设用户u和用户v都同属于倒排表中K个物品对应的用户列表,有C[u][v] = K
。最终计算处用户的兴趣相似性矩阵W
。
def UserSimilarity(train, K, N):
'''
:params: train, 训练数据集
:params: K, 超参数,设置取TopK相似用户数目
:params: N, 超参数,设置取TopN推荐物品数目
:return: GetRecommendation, 推荐接口函数
'''
# 计算item->user的倒排索引
item_users = {}
for user, items in train.items():
for i in items.keys():
if i not in item_users:
item_users[i] = set()
item_users[i].add(user)
# 计算用户间的互动次数
sim = {}
num = {}
W = {}
for i, users in item_users.items():
for u in users:
num[u] += 1
if u not in sim:
sim[u] = {}
for v in users:
if v == u:
continue
if v not in sim[u]:
sim[u][v] = 0
sim[u][v] += 1
# 计算用户相似度矩阵
for u, related_users in sim:
for v, cuv in related_users.items():
W[u][v] = cuv/math.sqrt(num[u] * num[v])
得到了与用户A兴趣相似的用户B之后,依次得到B用户评分最高的物品且A没有浏览过的,计算出用户A对物品的感兴趣程度。
# 按照相似度排序
sorted_user_sim = {k: list(sorted(v.items(), key=lambda x: x[1], reverse=True))
for k, v in W.items()}
# 获取接口函数
def GetRecommendation(user):
items = {}
seen_items = set(train[user])
for u, _ in sorted_user_sim[user][:K]:
for item in train[u]:
# 要去掉用户见过的
if item not in seen_items:
if item not in items:
items[item] = 0
# 如果存在评分,这里就是items[item] += W[user][u]*rvi
items[item] += W[user][u]
recs = list(sorted(items.items(), key=lambda x: x[1], reverse=True))[:N]
return recs
以上就是基本的UserCF算法,关键在于K值的选取。
之前的算法在计算用户兴趣相似度是采用的是最简单的余弦相似度公式,这个方法存在的问题是**两个用户对热门物品的喜爱不能很好的表现兴趣的相似性,对冷门物品的喜爱更可以反应问题 **。因此可以添加对物品热门程度的惩罚项。
惩罚了用户u和用户v共同兴趣列表中热门物品对他们相似度的影响。称为User-IIF算法。
该算法可以在有效提高准确率召回率和覆盖率。
基于用户的协同过滤算法存在一些缺点,如随着网站的用户数目标越来越大,计算用户相似度矩阵讲更加困难,另外难以对推荐结果进行解释。
基于物品的协同过滤算法是业界最常用的算法。主要分析用户的行为记录计算物品之间的相似度。这种算法可以根据用户的历史行为对推荐行为进行解释。基于物品的协同过滤算法主要分为两步,计算为物品之间的相似度;根据物品相似度和用户的历史行为给用户生成推荐列表。
物品相似度:两个物品具有高相似度的原因是因为他们共同被很多用户喜欢,每个用户都通过历实兴趣列表给物品贡献了相似度。这里蕴含了一个假设,每个人喜欢的内容一般都局限与几个领域。
与UserCF算法类似,用ItemCF算法计算物品相似度时也可建立用户-物品的倒排表,对每个用户建立一个包含他喜欢的物品的列表。
得到了物品相似度,进一步可以计算用户u对物品j的兴趣:
整个算法的原理可以表示为:
ItemCF算法的精度需要选择合适的K值,并且流行度存在一个与UserCF不同的特点在于,随着K的增加,流行度对增加, 但是当K大到一定程度时,流行度不在明显变化。K值得增加会降低覆盖率。
存在一些过分活跃的用户,不满足我们的假设,每个用户的兴趣数量都是有限且少量的。这部分广泛兴趣的用户应该被惩罚项。
这个算法与UserCF中对热门项目的惩罚是相似的。同时在实际的应用中,为了避免相似矩阵过度稠密,一般直接忽略这种用户的兴趣列表。这种带有惩罚项的算法称为ItemCF-IUF
。可以小幅度优化算法。
提高了覆盖率和降低了流行度。
归一化的意义在于可以增加推荐的准确度,提高推荐的覆盖率和多样性。举个例子,物品分为两类A,B,A类物品类内的相似度为0.5,B类物品的类内相似度为0.6,且AB的类间相似度为0.2。如果用户历史行为有五个A类,有五个B类。那么进行推荐时就会全是B类,因为相似度的数值更高。
一般来说,热门的类的类内物品的相似度较大,如果不进行归一化,就会推荐热门类的物品,导致覆盖率降低。
User方法给用户推荐那些与他有共同兴趣爱好的用户喜欢的物品,而Item给用户推荐的是之前喜欢的物品类似的物品。User方法推荐结果着重于反映于用户兴趣相似的小群体的热点,更加社会化;而Item着重维护用户的历史兴趣,反映了用户的兴趣传承。
User方法更适合新闻领域等具有时效性的,而且需要维护一个相对小的用户的相似度表即可,Item方法适合图书电影网站等,用户兴趣持久且固定,可以维护一个物品相似表
还需要考虑一个典型的问题,如看新闻联播的人一般都看黄金时段的电视剧,但是这两个并不具有高相似度,这时仅仅依靠用户行为数据是无法区分的,需要依靠引入物品的内容数据解决。这就是不是协同过滤的领域了。
核心思想是通过隐含的特征联系用户的兴趣和物品。
LFM通过下式计算用户u对物品i的兴趣:
p u , k p_{u,k} pu,k度量了用户u的兴趣和第k个隐类的关系, q i , k q_{i,k} qi,k反应了第k个隐类与物品i之间的关系。这两个参数的得到可以通过机器学习得到,需要一个训练集,对于每个用户u都包含了用户u喜欢的物品和不感兴趣的物品。更适合在显性反馈数据上(评分数据)上训练。对于只有正样本(用户喜欢的物品)的隐性反馈数据集,效果一般。
对于隐式反馈数据集,负样本的采样应该采用以下原则:
用过求解优化问题,可以得到最终结果。
在LFM中,重要的参数有四个,隐特征的个数F,学习率alpha,正则化参数lambda,正负样本比例ratio。其中,正负样本比例对性能的影响最大。因此固定设置,F = 100, alpha = 0.02, lambda = 0.01.
随着负样本数量的增加,导致了覆盖率降低,流行度增加,因此负样本的比例影响了推荐算法发掘长尾的能力。LFM算法的性能一般是要优于前面两个算法的,但是当数据量稀疏时,性能会下降。
缺点:
LFM在实际的使用中存在一些问题,如很难实现实时的推荐,LFM模型在每次训练时都需要扫描全部的用户行为,才能计算处用户的隐类向量( p u p_u pu)和物品的隐类向量( q i q_i qi)。而且需要反复迭代才能得到比较好的性能。 因此当用于新闻推荐时,存在明显的冷启动问题。
前一部分时传统的ItemCF, x u x_u xu表示用户的历史兴趣, y i y_i yi表示额物体的属性,可以利用新闻的关键词等信息对新闻进行粗略的划分,这部分每天只需要计算一次; p u , q i p_u, q_i pu,qi时根据实时的用户最近几个小时的行为训练LFM得到的。
离线计算的空间复杂度:
UserCF最大,Lfm最小。
离线训练的时间复杂度:
LFM的时间复杂度要高于基于邻域的方法,主要是因为需要多次迭代。
** 实时推荐能力**
邻域的方法对于实时推荐能力比较好,LFM方法无法进行实时推荐。
推荐解释能力
ItemCF的推荐解释能力很好。
相关性高的一对顶点一般具有如下特征:
随机游走的方法是说,首先我有alpha的概率绝对是否前进,如果前进就按照均匀分布随机选择一个节点。否则重新开始。最终会收敛到一个数字(感觉很类似马尔可夫啊)
但是随机游走的方法存在缺点,时间复杂度很高