这里加点东西:有利于理解
1基于CF的推荐算法
1.1算法简介
CF(协同过滤)简单来形容就是利用兴趣相投的原理进行推荐,协同过滤主要分两类,一类是基于物品的协同过滤算法,另一种是基于用户的协同过滤算法,这里主要介绍基于物品的协同过滤算法。
给定一批用户,及一批物品,记Vi表示不同用户对物品的评分向量,那么物品i与物品j的相关性为:
上述公式是利用余弦公式计算相关系数,相关系数的计算还有:杰卡德相关系数、皮尔逊相关系数等。
计算用户u对某一物品的偏好,记用户u对物品i的评分为score(u,i),用户u对物品i的协同过滤得分为rec(u,j)。
1.2业务实践
以购物篮子为例,业务问题:根据用户的历史购买商品记录,给用户推荐一批商品,协同过滤算法实现方法如下。
记buyers表示用户购买商品的向量,记为 其中表示全库用户集合,表示用户对商品的得分,定义如下:
-
Step1:计算物品之间的相关系数
记buyersi表示用户购买商品的向量,记buyersi=(…,bu,i,…) u∈U为,其中U表示全库用户集合,bu,i表示用户u对商品i的得分,定义如下:
那么商品i与商品j的相关系数如下:
上述公式是是利用余弦公式计算相关性,含义是商品的用户购买向量夹角越小越相似。此外也可以运用皮尔逊、杰卡德、自定义公式计算相关性,这里不一一列举。
-
Step2:计算用户对商品的协同过滤得分
给定一个用户u,设该用户历史购买商品记录的向量为historyu=(…,hu,i,…) ,i∈I其中I表示所有商品的集合:
计算给定一个物品j的协同过滤得分为:
-
Step3:给用户推荐商品
通过Step2计算用户对全库商品的协同过滤得分,取得分top 10展示给用户。
基于物品的协同过滤(item-based collaborative filtering)算法是目前业界应用最多的算法。无论是亚马逊网,还是Netflix、Hulu、YouTube,其推荐算法的基础都是该算法。
基于用户的协同过滤算法在一些网站(如Digg)中得到了应用,但该算法有一些缺点。首先,随着网站的用户数目越来越大,计算用户兴趣相似度矩阵将越来越困难,其运算时间复杂度和空间复杂度的增长和用户数的增长近似于平方关系。其次,基于用户的协同过滤很难对推荐结果作出解释。
基于物品的协同过滤算法给用户推荐那些和他们之前喜欢的物品相似的物品。比如,我们知道樱桃小丸子和小玉都喜欢葡萄和西瓜,那么我们就认为葡萄和西瓜有较高的相似度,在花伦选择了西瓜的情况下,我们会把葡萄推荐给花伦。
ItemCF算法并不利用物品的内容属性计算物品之间的相似度,它主要通过分析用户的行为记录计算物品之间的相似度。该算法认为,物品A和物品B具有很大的相似度是因为喜欢物品A的用户大都也喜欢物品B。
基于物品的协同过滤算法主要分为两步:
A.对于目标用户及其待评分的物品,根据用户对物品的历史偏好数据,计算物品与其他已评分物品之间的相似度 Sim(j,i),找到与物品相似度的物品合集N(u);
B. 根据所有物品 N(u) 的评分情况,选出N(u)中目标用户可能喜欢的且没有观看过的推荐给目标用户并预测评分。
适用性
适用于物品数明显小于用户数的场合; 长尾物品丰富,用户个性化需求强烈的领域。
#获取一个最匹配的n个用户,或者计算一个物品最匹配的n个物品,得到的是topN的相似度高的用户或物品
def topMatches(prefs,name,user=True,similarity=sim_pearson,n=5):
columns = list(prefs.columns)
if user:
others = [other for other in set(prefs[columns[0]]) if other!=name]
else:
others = [other for other in set(prefs[columns[1]]) if other!=name]
scores = [similarity(prefs,name,other,user) for other in others]
other_scores = pd.Series(scores,index=others).sort_values(ascending=False)[:n]
return other_scores
topMatches(criticsdf,name='Toby')
#构建物品比较数据集 ,形如{'Snakes on a Plane': {'Lady in the Water': 0.2222222222222222,··}}
def calculateSimilarItems(frame,n=5,similarity=sim_distance,TopN=5):
columns = list(frame.columns)
#建立字典,以给出与这些item最为相近的item
result={}
# 以item为中心进行转置
#itemPrefs=prefs.T
c=0
li = 0
for item in set(frame[columns[1]]):
#针对大数据集更新状态变量
scores={}
c+=1
# print(c)
# if c%100==0:
# print("%d / %d" % (c,len(itemPrefs)))
# print('----------')
# 寻找最为相近的物品
topn=topMatches(frame,name=item,similarity=similarity,user=False)
for user,score in zip(list(topn.index),list(topn)):
scores[user]=score
result[item]=scores
# itemSim =pd.DataFrame(result).stack()
# rate=list(itemSim)
# source=[]
# targe=[]
# for i,j in list(itemSim.index):
# source.append(i)
# targe.append(j)
# sim = pd.DataFrame(np.array([source,targe,rate]).T,columns=['sourceitem','targeitem','similiraty']).drop_duplicates()
return result
itemSim=calculateSimilarItems(criticsdf)
print(itemSim)
def getRecommendedItems(frame,user,itemMatch,TopN=5):
#把评分topn的产品推荐给目标user
columns = list(frame.columns)
userRating=frame[frame[columns[0]]==user][[columns[1],columns[2]]].drop_duplicates()#user为要给他推荐产品的用户
userRatings=pd.Series(list(userRating.iloc[:,1]),index=userRating.iloc[:,0])
print(pd.DataFrame(itemMatch).loc[userRatings.index])
rec=pd.DataFrame(itemMatch).loc[userRatings.index].dropna(axis=1)
#item评分加权和
w_sum = rec.mul(userRatings,axis=0).sum()
sim_sum=rec.sum()
#计算加权平均
rankings = (w_sum/sim_sum).sort_values(ascending=False)[:TopN]
return rankings
getRecommendedItems(criticsdf,'Toby',itemMatch=itemSim)