基于邻域的算法
基于邻域的算法分为两大类,一类是基于用户的协同过滤算法,另一类是基于物品的协同过滤算法。
一、基于用户的协同过滤算法:
基于用户的协同过滤算法主要包括两个步骤
(1) 找到和目标用户兴趣相似的用户集合
(2) 找到这个集合中的用户喜欢的,且目标用户没有听说过的物品推荐给目标用户
步骤(1)的关键就是计算两个用户的兴趣相似度。给定用户u和用户v,令N(u)表示用户u曾经有过正反馈的物品集合,令N(v)为用户v曾经有过正反馈的物品集合。那么,我们可以通过如下的Jaccard公式简单地计算u和v的兴趣相似度:
或者通过余弦相似度计算:
train = {'A':set(['a','b','d']),'B':set(['a','c']),'C':set(['b','e']),'D':set(['c','d','e'])} #余弦相似度 def UserSimilarity(train): W = {} for u in train.keys(): for v in train.keys(): if u == v: continue W.setdefault(u,{}) W[u].setdefault(v,0) W[u][v] = len(train[u] & train[v]) W[u][v] /= math.sqrt(len(train[u]) * len(train[v]) * 1.0) return W print UserSimilarity(train)
该代码对两两用户都利用余弦相似度计算相似度。这种方法的时间复杂度是O(|U|*|U|),这在用户数很大时非常耗时。事实上,很多用户相互之间并没有对同样的物品产生过行为,即很多时候
可以首先建立物品到用户的倒排表,对于每个物品都保存对该物品产生过行为的用户列表.这样来自同一物品映射的两个用户肯定是有交集的。这样一来只用计算有交集的用户的相似度,其他初始化为0即可
def UserSimilarity1(train): #建立倒排表 item_users = dict() for u,items in train.items(): for i in items: if i not in item_users: item_users[i] = set() item_users[i].add(u) #记录用户U V 共有的物品个数 C = dict() #记录每个用户所拥有的物品个数 N = dict() for i ,users in item_users.items(): for u in users: N.setdefault(u,0) N[u] += 1 for v in users: if u == v: continue C.setdefault(u,{}) C[u].setdefault(v,0) C[u][v] += 1 #相似矩阵 W = {} for u , related_users in C.items(): for v ,cur in related_users.items(): W.setdefault(u,{}) W[u].setdefault(v,0) W[u][v] = cur / math.sqrt(N[u] * N[v]) return W
得到用户之间的兴趣相似度后, UserCF算法会给用户推荐和他兴趣最相似的K个用户喜欢的物品。如下的公式度量了UserCF算法中用户u对物品i的感兴趣程度:
S(u, K)包含和用户u兴趣最接近的K个用户, N(i)是对物品i有过行为的用户集合, wuv是用户u和用户v的兴趣相似度, rvi代表用户v对物品i的兴趣,因为使用的是单一行为的隐反馈数据,所以所有的rvi=1。
UserCF只有一个重要的参数K,即为每个用户选出K个和他兴趣最相似的用户,然后推荐那K个用户感兴趣的物品。
准确率和召回率:推荐系统的精度指标(准确率和召回率)并不和参数K成线性关系在MovieLens数据集中,选择K=80左右会获得比较高的准确率和召回率。因此选择合适的K对于获得高的推荐系统精度比较重要。当然,推荐结果的精度对K也不是特别敏感,只要选在一定的区域内,就可以获得不错的精度。
流行度:可以看到,在3个数据集上K越大则UserCF推荐结果就越热门。这是因为K决定了UserCF在给你做推荐时参考多少和你兴趣相似的其他用户的兴趣,那么如果K越大,参考的人越多,结果就越来越趋近于全局热门的物品
覆盖率:可以看到,在3个数据集上, K越大则UserCF推荐结果的覆盖率越低。覆盖率的降低是因为流行度的增加,随着流行度增加, UserCF越来越倾向于推荐热门的物品,从而对长尾物品的推荐越来越少,因此造成了覆盖率的降低。
用户相似度计算的改进
两个用户对冷门物品采取过同样的行为更能说明他们兴趣的相似度。如下公式,根据用户行为计算用户的兴趣相似度:
该公式通过惩罚了用户u和用户v共同兴趣列表中热门物品对他们相似度的影响,基于上述用户相似度公式的UserCF算法记为User-IIF算法,UserCF-IIF在各项性能上略优于UserCF
上述公式记号有问题,N(i)应该是物品i对应的用户个数。
二、基于物品的协同过滤算法
基于物品的协同过滤(item-based collaborative filtering)算法是目前业界应用最多的算法。基于物品的协同过滤算法 (简称ItemCF)给用户推荐那些和他们之前喜欢的物品相似的物品。
ItemCF算法并不利用物品的内容属性计算物品之间的相似度,它主要通过分析用户的行为记录计算物品之间的相似度。该算法认为,物品A和物品B具有很大的相似度是因为喜欢物品A的用户大都也喜欢物品B.
基于物品的协同过滤算法主要分为两步。
(1) 计算物品之间的相似度。
(2) 根据物品的相似度和用户的历史行为给用户生成推荐列表。
我们可以用下面的公式定义物品的相似度:
分母|N(i)|是喜欢物品i的用户数,而分子是同时喜欢物品i和物品j的用户.如果物品j很热门,很多人都喜欢,那么Wij就会很大,接近1。因此,该公式会造成任何物品都会和热门的物品有很大的相似度.为了避免推荐出热门的物品,可以用下面的公式:
这个公式惩罚了物品j的权重,因此减轻了热门物品会和很多物品相似的可能性。
在得到物品之间的相似度后, ItemCF通过如下公式计算用户u对一个物品j的兴趣:
这里N(u)是用户喜欢的物品的集合, S(j,K)是和物品j最相似的K个物品的集合, wji是物品j和i的相似度, rui是用户u对物品i的兴趣。(对于隐反馈数据集,如果用户u对物品i有过行为,即可令rui=1。)
该公式的含义是,和用户历史上感兴趣的物品越相似的物品,越有可能在用户的推荐列表中获得比较高的排名。
用户活跃度对物品相似度的影响
John S. Breese在论文中提出了一个称为IUF(Inverse User Frequence),即用户活跃度对数的倒数的参数,他也认为活跃用户对物品相似度的贡献应该小于不活跃的用户,他提出应该增加IUF参数来修正物品相似度的计算公式:
上面的公式只是对活跃用户做了一种软性的惩罚,但对于很多过于活跃的用户,为了避免相似度矩阵过于稠密,我们在实际计算中一般直接忽略他的兴趣列表,而不将其纳入到相似度计算的数据集中。将上面的算法记为ItemCF-IUF。
物品相似度的归一化
如果将ItemCF的相似度矩阵按最大值归一化,可以提高推荐的准确率(为什么?)。 如果已经得到了物品相似度矩阵w,那么可以用如下公式得到归一化之后的相似度矩阵w':
归一化的好处不仅仅在于增加推荐的准确度,它还可以提高推荐的覆盖率和多样性。
三、UserCF和ItemCF的综合比较
UserCF给用户推荐那些和他有共同兴趣爱好的用户喜欢的物品,而ItemCF给用户推荐那些和他之前喜欢的物品类似的物品。从这个算法的原理可以看到, UserCF的推荐结果着重于反映和用户兴趣相似的小群体的热点,而ItemCF 的推荐结果着重于维系用户的历史兴趣。换句话说, UserCF的推荐更社会化,反映了用户所在的小型兴趣群体中物品的热门程度,而ItemCF的推荐更加个性化,反映了用户自己的兴趣传承。
热门程度和时效性是个性化新闻推荐的重点,而个性化相对于这两点略显次要。UserCF可以给用户推荐和他有相似爱好的一群其他用户今天都在看的新闻,这样在抓住热点和时效性的同时,保证了一定程度的个性化。这是Digg在新闻推荐中使用UserCF的最重要原因。
UserCF适合用于新闻推荐的另一个原因是从技术角度考量的。因为作为一种物品,新闻的更 新非常快,每时每刻都有新内容出现,而ItemCF需要维护一张物品相关度的表,如果物品更新很快,那么这张表也需要很快更新,这在技术上很难实现。绝大多数物品相关度表都只能做到一天一次更新,这在新闻领域是不可以接受的。而UserCF只需要用户相似性表,虽然UserCF对于新用户也需要更新相似度表,但在新闻网站中,物品的更新速度远远快于新用户的加入速度,而且对于新用户,完全可以给他推荐最热门的新闻,因此UserCF显然是利大于弊。