基于用户人口属性和行为数据设计的推荐算法,称为协同过滤算法。此方法主要根据用户的历史行为,寻找用户或物品的近邻集合,以此计算用户对物品的偏好,包括基于领域,图,关联规则,知识的推荐算法,其中最广泛应用是基于领域的方法,在实践中往往是上述几种方法的混合应用。
基于领域的推荐算法
基于领域的推荐算法主要包含两种:基于用户的协同过滤算法(UserCF)和基于物品的协同过滤算法(ItemCF)基于用户的协同过滤计算用户感兴趣相似度,基于物品的协同过滤算法计算与用户偏好的物品相似的物品。
(1)基于领域的推荐算法
基于酸奶的协同过滤算法为用户推荐兴趣相似的其他用户喜欢的物品。算法的关键是计算两个用户的兴趣相似度。计算用户相似度的常用方法有余弦相似性,皮尔森系数和修正的余弦相似性。
算法步骤如下:
- 找到与目标用户兴趣相似的用户集合;
- 找到这个集合中的用户喜欢的,且目标用户没有用过的物品,推荐给目标用户。
下面举一个简单的例子说明
下表是基于用户的协同过滤推荐示例,可以看到用户阿与用户Ç所喜欢的物品具有较多的交集,即两个用户具有相似性,那么用户Ç喜欢的物品很有可能用户甲也会喜欢,而用户ç喜欢物品d,则可以向用户甲推荐物品D.
用户/物品 | 物品一个 | 物品乙 | 物品ç | 物品d |
用户一 | X | X | 推荐 | |
用户乙 | X | |||
用户ç | X | X |
X |
计算用户兴趣相似度时,要避免热门物品自带马太效应的影响,即大部分用户可能都对热门的物品表现出喜欢的状况,但是这些用户之间并非一类人,因为所谓的热门物品区分度较弱。
基于用户的协同过滤算法的缺点是随着用户数目增大,计算用户兴趣相似度越来越复杂,时间和空间复杂度与用户数接近于平方关系。所以一般采用离线方式进行推荐,即当用户产生新的行为时,不会立即进行计算,所以推荐结果并不会马上发生变化。此外,这一算法是基于隐式群体的兴趣进行推荐,可解释性不强。这一算法适用于用户数据比较稳定的场景,即通过群体的兴趣来代表用户个体的兴趣,一旦群体的兴趣确立,就可以认为个体用户服从此兴趣,由此向其进行推荐,结果一般较准确。
(2)基于物品的协同过滤算法
基于物品的协同过滤算法是依据用户喜欢的物品向其推荐与之相似的其他物品,属于基础的推荐算法,集成在各类电商平台的推荐系统中。与基于内容的推荐算法相比,该。算法是通过用户的行为计算物品之间的相似度而基于内容的推荐算法计算用户喜欢的物品的内容共同特征,作为用户的偏好描述,然后寻找与此特征相似的其他物品。
下面举一个简单的例子说明一下
两个物品是相似的,可能是因为它们共同被很多用户喜欢,也就是说,每个用户都可以通过其历史兴趣列表给物品“贡献”相似度。下表中用户对物品甲和物品乙都表现了相同的用户行为,即喜欢这两种物品,而且这两种物品与物品d具有一定的相似性(某些属性取值相同或相近),那么可以向用户推荐物品D.
用户/物品 | 物品一个 | 物品乙 | 物品ç | 物品d |
用户1 | X | X | ||
用户2 | X | X | 推荐 | |
用户3 | X | X | X |
基于物品的协同推荐在物品数量较少时,物品间相似度的计算量不大,主要应用于长尾物品领域,在用户行为较少时,只要用户有少数点击行为就可以向其推荐相似的物品,所以可以用于解决用户冷启动问题,并且这一过程是基于用户的向其推荐的,推荐结果的可解释性较好。
下面写一个电影的推荐系统代码如下:
- #!/usr/bin/python
- # -*- coding: UTF-8 -*-
- '''
- 基于用户的推荐算法
- '''
- from math import sqrt,pow
- import operator
- class UserCf():
-
- #获得初始化数据
- def __init__(self,data):
- self.data=data
-
- #通过用户名获得电影列表,仅调试使用
- def getItems(self,username1,username2):
- return self.data[username1],self.data[username2]
-
- #计算两个用户的皮尔逊相关系数
- def pearson(self,user1,user2):#数据格式为:电影,评分 {'Snakes on a Plane': 4.5, 'You, Me and Dupree': 1.0, 'Superman Returns': 4.0}
- sumXY=0.0
- n=0
- sumX=0.0
- sumY=0.0
- sumX2=0.0
- sumY2=0.0
- try:
- for movie1,score1 in user1.items():
- if movie1 in user2.keys():#计算公共的电影的评分
- n+=1
- sumXY+=score1*user2[movie1]
- sumX+=score1
- sumY+=user2[movie1]
- sumX2+=pow(score1,2) #score1的平方
- sumY2+=pow(user2[movie1],2)
-
- molecule=sumXY-(sumX*sumY)/n
- denominator=sqrt((sumX2-pow(sumX,2)/n)*(sumY2-pow(sumY,2)/n))
- r=molecule/denominator
- except Exception as e:
- print ("异常信息:",e.message)
- return None
- return r
-
- #计算与当前用户的距离,获得最临近的用户
- def nearstUser(self,username,n=1):
- distances={}#用户,相似度
- for otherUser,items in self.data.items():#遍历整个数据集n
- if otherUser not in username:#非当前的用户
- distance=self.pearson(self.data[username],self.data[otherUser])#计算两个用户的相似度
- distances[otherUser]=distance
- sortedDistance=sorted(distances.items(),key=operator.itemgetter(1),reverse=True)#最相似的N个用户
- print ("排序后的用户为:",sortedDistance)
- return sortedDistance[:n]
-
-
- #给用户推荐电影
- def recomand(self,username,n=1):
- recommand={}#待推荐的电影
- for user,score in dict(self.nearstUser(username,n)).items():#最相近的n个用户
- print ("推荐的用户:",(user,score))
- for movies,scores in self.data[user].items():#推荐的用户的电影列表
- if movies not in self.data[username].keys():#当前username没有看过
- print ("%s为该用户推荐的电影:%s"%(user,movies))
- if movies not in recommand.keys():#添加到推荐列表中
- recommand[movies]=scores
-
- return sorted(recommand.items(),key=operator.itemgetter(1),reverse=True)#对推荐的结果按照电影评分排序
-
- if __name__=='__main__':
- users = {'Lisa Rose': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.5,
- 'Just My Luck': 3.0, 'Superman Returns': 3.5, 'You, Me and Dupree': 2.5,
- 'The Night Listener': 3.0},
-
- 'Gene Seymour': {'Lady in the Water': 3.0, 'Snakes on a Plane': 3.5,
- 'Just My Luck': 1.5, 'Superman Returns': 5.0, 'The Night Listener': 3.0,
- 'You, Me and Dupree': 3.5},
-
- 'Michael Phillips': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.0,
- 'Superman Returns': 3.5, 'The Night Listener': 4.0},
-
- 'Claudia Puig': {'Snakes on a Plane': 3.5, 'Just My Luck': 3.0,
- 'The Night Listener': 4.5, 'Superman Returns': 4.0,
- 'You, Me and Dupree': 2.5},
-
- 'Mick LaSalle': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
- 'Just My Luck': 2.0, 'Superman Returns': 3.0, 'The Night Listener': 3.0,
- 'You, Me and Dupree': 2.0},
-
- 'Jack Matthews': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
- 'The Night Listener': 3.0, 'Superman Returns': 5.0, 'You, Me and Dupree': 3.5},
-
- 'Toby': {'Snakes on a Plane': 4.5, 'You, Me and Dupree': 1.0, 'Superman Returns': 4.0}
- }
-
- userCf=UserCf(data=users)
- recommandList=userCf.recomand('Toby', 2)
- print ("最终推荐:%s"%recommandList)
运行结果如下:
<script>
(function(){
function setArticleH(btnReadmore,posi){
var winH = $(window).height();
var articleBox = $("div.article_content");
var artH = articleBox.height();
if(artH > winH*posi){
articleBox.css({
'height':winH*posi+'px',
'overflow':'hidden'
})
btnReadmore.click(function(){
if(typeof window.localStorage === "object" && typeof window.csdn.anonymousUserLimit === "object"){
if(!window.csdn.anonymousUserLimit.judgment()){
window.csdn.anonymousUserLimit.Jumplogin();
return false;
}else if(!currentUserName){
window.csdn.anonymousUserLimit.updata();
}
}
articleBox.removeAttr("style");
$(this).parent().remove();
})
}else{
btnReadmore.parent().remove();
}
}
var btnReadmore = $("#btn-readmore");
if(btnReadmore.length>0){
if(currentUserName){
setArticleH(btnReadmore,3);
}else{
setArticleH(btnReadmore,1.2);
}
}
})()
</script>
</article>