ItemCF更加看重与维系用户的历史兴趣,会给用户推荐与那些他们之前喜欢的物品相似的物品。也就是说ItemCF需要计算物品之间的相似度,而不像UserCF去计算用户的相似度。比如,你购买过物品A,通过计算物品B与物品A有很大的相似度,那么就会给你推荐物品A. 而这里计算物品之间的相似度,也不是利用物品的内容属性,而是通过分析用户的行为记录来计算的。该算法认为,之所以A与B有很大的相似性,是因为喜欢A的用户也喜欢B.
ItemCF主要分两步:
计算两个物品之间的相似度可以用下面的公式:
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
从上面我们知道,每个用户都会为物品相似度做出贡献。考虑到活跃用户对物品相似度的贡献要小于要不活跃用户的贡献,本书中给出了修正的相似度计算公式,对活跃的用户做了一种软性的惩罚,
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
对于相似度,文章又指出如果可以把得出来的相似度按照最大值归一化,可以提高推荐的准确率,覆盖率和多样性。即
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 这块的论文了,再补些想法。