您的位置:首页 > 其它

基于邻域的协同过滤算法(二)

2016-07-02 17:44 134 查看

基于物品的协同过滤算法(ItemCF)

  ItemCF更加看重与维系用户的历史兴趣,会给用户推荐与那些他们之前喜欢的物品相似的物品。也就是说ItemCF需要计算物品之间的相似度,而不像UserCF去计算用户的相似度。比如,你购买过物品A,通过计算物品B与物品A有很大的相似度,那么就会给你推荐物品A. 而这里计算物品之间的相似度,也不是利用物品的内容属性,而是通过分析用户的行为记录来计算的。该算法认为,之所以A与B有很大的相似性,是因为喜欢A的用户也喜欢B.

  ItemCF主要分两步:

计算物品之间的相似度。

根据物品的相似度和用户的历史行为给用户生成推荐列表。

   计算两个物品之间的相似度可以用下面的公式:

wij=∣N(i)∩N(j)∣∣N(i)∣∣N(j)∣‾‾‾‾‾‾‾‾‾‾‾‾√

这里,我们看到,共同喜欢这两个物品的用户数目越多,就代表这两个物品的相似度越大。这个应该容易理解些。 计算时,需要先建立用户-物品倒排表,是为了降低时间复杂度,直接对那些同时出现在用户行为列表中的物品进行计数,而不去考虑 ∣N(i)∩N(j)∣=0 的情形。

相似度计算的python代码是:

from math import *
def ItemSimilarity(train):
C=dict()#分子
N=dict() #分母
for u, items in train.items():
for i in items:
if i not in N:
N[i] = 1
else:
N[i] += 1
for j in items:
if i != j:
if (i, j) not in C:
C[(i, j)] = 1
else:
C[(i, j)] += 1
W = dict()
for (i,j), val in C.items():
if i not in W:
W[i] = {}
W[i][j]= val / sqrt(N[i] * N[j])
return W


   从上面我们知道,每个用户都会为物品相似度做出贡献。考虑到活跃用户对物品相似度的贡献要小于要不活跃用户的贡献,本书中给出了修正的相似度计算公式,对活跃的用户做了一种软性的惩罚,

wij=∑u∈N(i)∩N(j)1ln(1+∣N(u)∣)∣N(i)∣∣N(j)∣‾‾‾‾‾‾‾‾‾‾‾‾√.

这里说活跃用户对物品相似度的贡献小于不活跃的用户。我是这么理解的,一个活跃的用户买了很多物品,会涉及到很多类型,那么这里面任意两个物品属于同一个类型的概率就比较小,这是假相似。而两个物品被很多不活跃的用户买了,才说明它们是真的相似。另外,对于过于活跃的用户,为了避免相似度矩阵过于稠密,在实际计算中一般直接忽略他的兴趣列表。

下面是修正后的物品相似度计算代码:

from math import *
def ItemSimilarity2(train):
C=dict() #分子
N=dict() #分母
for u, items in train.items():
for i in items:
if i not in N:
N[i]=1
else:
N[i]+=1
for j in items:
if i !=j:
if (i,j) not in C:
C[(i,j)]=1/log(1+len(items))
else:
C[(i,j)]+=1/log(1+len(items))
W=dict()
for (i,j), val in C.items():
if i not in W:
W[i]={}
W[i][j]=val/sqrt(N[i]*N[j])
return W


  对于相似度,文章又指出如果可以把得出来的相似度按照最大值归一化,可以提高推荐的准确率,覆盖率和多样性。即

w′ij=wijmax wij

归一化这块理解的还不好,需要再查查资料

  相似度计算完后,就是要给用户生成推荐列表了。这里类似于UserCF, 计算用户对物品的兴趣度,然后推荐给用户兴趣度高的。通过下面的公式计算用户u对物品j的兴趣:

puj=∑i∈N(u)∩S(j,K)wjirui

这里,N(u)是u喜欢的物品的集合,S(j,k)是和物品j最形似的K个物品的集合,wji是j和i的相似度,rui为u对i的兴趣(对于隐反馈数据集,u对i有过行为,可令rui=1)。下面的程序封装了计算兴趣度和推荐:

def ItemRecommendation(user, train, W, N, K=10):
rank = dict()
user_items = train[user]
for i in user_items:
for j, wij in sorted(W[i].items(), key=lambda x: x[1],reverse=True)[0:K]:
if j not in user_items:
if j not in rank:
rank[j] = wij * 1
else:
rank[j] += wij * 1
rank = sorted(rank.items(), key=lambda x: x[1], reverse=True)

rank = rank[:N]
return rank


   接下来就是通过计算准确率,召回率,覆盖率来研究 K对系统的影响。计算公式已经在上一篇文章中给出,这里给出python代码

#准确率
def ItemPrecision(train, test, N, K):
hit = 0
alls = 0
W = ItemSimilarity(train)
for user in train.keys():
te_user_item = test[user]
recomRank = ItemRecommendation(user, train, W, N, K)
for recom_item, w in recomRank:
if recom_item in te_user_item:
hit += 1
alls += N
return hit * 1.0 / alls
#召回率
def ItemRecall(train, test, N):
hit = 0
alls = 0
W = ItemSimilarity(train)
for user in train.keys():
te_user_item = test[user]
recomRank = ItemRecommendation(user, train, W, N)
for recom_item, w in recomRank:
if recom_item in te_user_item:
hit += 1
alls += len(te_user_item)
return hit * 1.0 / alls
#覆盖率
def ItemCoverage(train, N):
recommend_items = set()
all_items = set()
W = ItemSimilarity(train)
for user in train.keys():
for item in train[user]:
all_items.add(item)
rank = ItemRecommendation(user, train, W, N)
for item in rank:
recommend_items.add(item[0])
return len(recommend_items) / (len(all_items) * 1.0)


ItemCF的大概思路应该就是这样。等看了ItemCF 这块的论文了,再补些想法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  协同过滤算法