http://my.oschina.net/zhangjiawen/blog/185625

1基于用户的协同过滤算法:

基于用户的协同过滤算法是推荐系统中最古老的的算法,可以说是这个算法的诞生标志了推荐系统的诞生。该算法在1992年被提出,并应用于邮件过滤系统,1994年被GroupLens用于新闻过滤。

在一个在线个性化推荐系统中,当一个用户A需要个性化推荐时,可以先找到和他有相似兴趣的其他用户,然后把那些用户喜欢的而用户A没有接触过的物品推荐给A。这种方法称为基于用户的协同过滤算法。

给定用户u和用户v,令N(u)表示用户u曾经有过正反馈的物品集合,通过余弦相似度计算用户的相似度。由于很多用户相互之间并没有对同样的物品产生过行为,即,因此可以先计算的用户对(u,v)。为此,可以首先建立物品到用户的倒查表,对于每个物品保存对该物品产生过行为的用户列表。令稀疏矩阵,假设用户u和用户v同时属于倒查表中K个物品对应的用户列表,就有(即用户u和v对相同物品产生正反馈的物品数),从而可以扫描倒查表中每个物品对应的用户列表,将用户列表中的两两用户对应的加1,最终就可以获得所有用户之间不为0的(也就是余弦相似度的分子)。

得到用户之间的兴趣相似度之后,基于用户的协同过滤算法(User Based Collaborative Filering)会给用户推荐和他兴趣最相似的K个用户喜欢的物品。如下公式度量了UserCF算法中用户u对物品i的感兴趣程度:

其中,S(u,k)包含和用户u兴趣相似度最接近的k个用户集合,N(i)是对物品i有过行为的用户集合,是用户u和用户v的兴趣相似度,代表用户v对物品i的兴趣,因为使用的是单一行为的隐反馈数据,因此为1。

根据以上思路,使用Python实现UserCF算法的代码如下:

import random
002 import math
003 class UserBasedCF:
004     def __init__(self,datafile = None):
005         self.datafile = datafile
006         self.readData()
007         self.splitData(3,47)
008          
009     def readData(self,datafile = None):
010     """
011     read the data from the data file which is a data set
012     """
013         self.datafile = datafile or self.datafile
014         self.data = []
015     for line in open(self.datafile):
016         userid,itemid,record,_ = line.split()
017         self.data.append((userid,itemid,int(record)))
018  
019     def splitData(self,k,seed,data=None,M = 8):
020         """
021         split the data set
022         testdata is a test data set
023         traindata is a train set 
024         test data set / train data set is 1:M-1
025         """
026         self.testdata = {}
027         self.traindata = {}
028         data = data or self.data
029         random.seed(seed)
030         for user,item, record in self.data:
031             if random.randint(0,M) == k:
032                 self.testdata.setdefault(user,{})
033                 self.testdata[user][item] = record
034             else:
035                 self.traindata.setdefault(user,{})
036                 self.traindata[user][item] = record
037      
038     def userSimilarityBest(self,train = None):
039     """
040     the other method of getting user similarity which is better than above
041     you can get the method on page 46
042     In this experiment,we use this method
043     """
044         train = train or self.traindata
045         self.userSimBest = dict()
046         item_users = dict()
047         for u,item in train.items():
048             for in item.keys():
049                 item_users.setdefault(i,set())
050                 item_users[i].add(u)
051         user_item_count = dict()
052         count = dict()
053         for item,users in item_users.items():
054             for in users:
055                 user_item_count.setdefault(u,0)
056                 user_item_count[u] += 1
057         for in users:
058             if == v:continue
059         count.setdefault(u,{})
060         count[u].setdefault(v,0)
061         count[u][v] += 1
062         for u ,related_users in count.items():
063             self.userSimBest.setdefault(u,dict())
064             for v, cuv in related_users.items():
065                 self.userSimBest[u][v] = cuv / math.sqrt(user_item_count[u] * user_item_count[v] * 1.0)
066      
067     def recommend(self,user,train = None,k = 8,nitem = 40):
068         train = train or self.traindata
069         rank = dict()
070         interacted_items = train.get(user,{})
071         for v ,wuv in sorted(self.userSimBest[user].items(),key = lambda x : x[1],reverse = True)[0:k]:
072             for i , rvi in train[v].items():
073                 if in interacted_items:
074                     continue
075                 rank.setdefault(i,0)
076                 rank[i] += wuv
077             return dict(sorted(rank.items(),key = lambda x :x[1],reverse = True)[0:nitem])
078  
079     def recallAndPrecision(self,train = None,test = None,k = 8,nitem = 10):
080     """
081     Get the recall and precision, the method you want to know is listed 
082     in the page 43
083     """
084     train = train or self.traindata
085     test = test or self.testdata
086     hit = 0
087     recall = 0
088     precision = 0
089     for user in train.keys():
090         tu = test.get(user,{})
091     rank = self.recommend(user, train = train,k = k,nitem = nitem)
092     for item,_ in rank.items():
093         if item in tu:
094             hit += 1
095     recall += len(tu)
096     precision += nitem
097     return (hit / (recall * 1.0),hit / (precision * 1.0))
098      
099     def coverage(self,train = None,test = None,k = 8,nitem = 10):
100         train = train or self.traindata
101         test = test or self.testdata
102         recommend_items = set()
103         all_items = set()
104         for user in train.keys():
105             for item in train[user].keys():
106                 all_items.add(item)
107         rank = self.recommend(user, train, k = k, nitem = nitem)
108         for item,_ in rank.items():
109             recommend_items.add(item)
110         return len(recommend_items) / (len(all_items) * 1.0)
111      
112     def popularity(self,train = None,test = None,k = 8,nitem = 10):
113     """
114     Get the popularity
115     the algorithm on page 44
116     """
117         train = train or self.traindata
118         test = test or self.testdata
119         item_popularity = dict()
120         for user ,items in train.items():
121             for item in items.keys():
122                 item_popularity.setdefault(item,0)
123                 item_popularity[item] += 1
124         ret = 0
125         = 0
126         for user in train.keys():
127             rank = self.recommend(user, train, k = k, nitem = nitem)
128         for item ,_ in rank.items():
129             ret += math.log(1+item_popularity[item])
130         += 1
131         return ret / (n * 1.0)
132  
133     def testUserBasedCF():
134         cf = UserBasedCF('u.data')
135         cf.userSimilarityBest()
136         print "%3s%20s%20s%20s%20s" % ('K',"recall",'precision','coverage','popularity')
137         for in [5,10,20,40,80,160]:
138             recall,precision = cf.recallAndPrecision( k = k)
139             coverage = cf.coverage(k = k)
140             popularity = cf.popularity(k = k)
141             print "%3d%19.3f%%%19.3f%%%19.3f%%%20.3f" % (k,recall * 100,precision * 100,coverage * 100,popularity)
142  
143 if __name__ == "__main__":
144 testUserBasedCF()

2 基于物品的协同过滤算法:

基于物品的协同过滤算法(Item-Based Collaborative Filtering)是目前业界应用最多的算法,亚马逊、Netflix、Hulu、YouTube都采用该算法作为其基础推荐算法。

基于用户的协同过滤算法有一些缺点:随着网站的用户数目越来越大,计算用户兴趣相似度矩阵将越来越困难,其运算时间复杂度和空间复杂度的增长和用户数的增长近似平方关心。并且,基于用户的协同过滤算法很难对推荐结果做出解释。因此亚马逊提出了基于物品的协同过滤算法。

基于物品的协同过滤算法给用户推荐那些和他们之前喜欢的物品相似的物品。不过ItemCF算法并不利用物品的内容属性计算物品之间的相似度,它主要通过分析用户的行为记录计算用户之间的相似度,也就是说物品A和物品B具有很大的相似度是因为喜欢物品A的用户大都也喜欢物品B(这一点也是基于物品的协同过滤算法和基于内容的推荐算法最主要的区别)。同时,基于物品的协同过滤算法可以利用用户的历史行为给推荐结果提供推荐解释,用于解释的物品都是用户之前喜欢的或者购买的物品。

“Customers Who Bought This Item Also Bought”(亚马逊显示相关物品推荐时的标题),从这句话的定义出发,利用以下公式定义物品之间的相似度:

其中N(i)是喜欢物品i的用户数,分子是同时喜欢物品i和物品j的用户数。这个公式惩罚了物品j的权重,减轻了热门物品会和很多物品相似的可能性(这样wij的值会很大,接近于1)。这个公式说明两个物品产生相似度是因为它们共同被很多用户喜欢,也就是说每个用户都可以通过他们的历史兴趣列表给物品“贡献”相似度。

和UserCF算法类似,用ItemCF算法计算物品相似度时也可以首先建立用户-物品倒排表,即对每个用户建立一个包含他喜欢的物品的列表,然后对于每个用户,将他物品列表中的物品两两在共现矩阵C中加1,最终就可以得到所有物品之间不为0的,也就是公式中的分子。

在得到物品之间的相似度后,ItemCF通过如下公式计算用户u对一个物品i的兴趣:

其中,N(u)是用户喜欢的物品集合,S(i,k)是和物品i最相似的k个物品的集合,是物品j和物品i的相似度,是用户u对物品i的兴趣,对于隐反馈数据集,如果用户u对物品i有过行为,即可令为1。

根据以上思路,使用Python实现ItemCF算法的代码如下:

001 import math
002 import random
003 class ItemBasedCF:
004     def __init__(self, datafile = None):
005         self.datafile = datafile
006         self.readData()
007         self.splitData(3,47)
008          
009     def readData(self,datafile = None):
010         self.datafile = datafile or self.datafile
011         self.data = []
012         file = open(self.datafile,'r')
013         for line in file.readlines()[0:100*1000]:
014             userid, itemid, record,_ = line.split()
015             self.data.append((userid,itemid,int(record)))
016              
017     def splitData(self,k,seed,data=None,M = 8):
018         self.testdata = {}
019         self.traindata = {}
020         data = data or self.data
021         random.seed(seed)
022         for user,item,record in self.data:
023             if random.randint(0,7== k:
024                 self.testdata.setdefault(item,{})
025                 self.testdata[item][user] = record
026             else:
027                 self.traindata.setdefault(item,{})
028                 self.traindata[item][user] = record
029                  
030 def ItemSimilarity(self, train = None):
031     train = train or self.traindata
032     self.itemSim = dict()
033     #user_items = dict()
034     item_user_count = dict() #item_user_count{item: likeCount} the number of users who like the item
035     count = dict() #count{i:{j:value}} the number of users who both like item i and j
036     for user, item in train.items(): #initialize the user_items{user: items}
037         for in item.keys():
038             item_user_count.setdefault(i,0)
039             item_user_count[i] += 1
040             for in item.keys():
041                 if == j:
042                     continue
043         count.setdefault(i,{})
044         count[i].setdefault(j,0)
045         count[i][j] += 1
046      for i, related_items in count.items():
047         self.itemSim.setdefault(i,dict())
048         for j, cuv in related_items.items():
049             self.itemSim[i].setdefault(j,0)
050             self.itemSim[i][j] = cuv / math.sqrt(item_user_count[i] * item_user_count[j] * 1.0)
051              
052 def recommend(self,user,train = None, k = 8, nitem = 40):
053     train = train or self.traindata
054     rank = dict()
055     ru = train.get(user,{})
056     for i,pi in ru.items():
057         for j,wj in sorted(self.itemSim[i].items(), key = lambda x:x[1], reverse = True)[0:k]:
058             if in ru:
059                 continue
060         rank.setdefault(j,0)
061         rank[j] += wj
062     #print dict(sorted(rank.items(), key = lambda x:x[1], reverse = True)[0:nitem])
063     return dict(sorted(rank.items(), key = lambda x:x[1], reverse = True)[0:nitem])
064      
065     def recallAndPrecision(self,train = None,test = None,k = 8,nitem = 10):
066     train = train or self.traindata
067     test = test or self.testdata
068     hit = 0
069     recall = 0
070     precision = 0
071     for user in train.keys():
072         tu = test.get(user,{})
073     rank = self.recommend(user,train = train,k = k,nitem = nitem)
074     for item,_ in rank.items():
075         if item in tu:
076             hit += 1
077             recall += len(tu)
078             precision += nitem
079     return (hit / (recall * 1.0),hit / (precision * 1.0))
080      
081     def coverage(self,train = None,test = None,k = 8,nitem = 10):
082         train = train or self.traindata
083         test = test or self.testdata
084         recommend_items = set()
085         all_items = set()
086         for user in train.keys():
087             for item in train[user].keys():
088                 all_items.add(item)
089         rank = self.recommend(user, train, k = k, nitem = nitem)
090         for item,_ in rank.items():
091             recommend_items.add(item)
092         return len(recommend_items) / (len(all_items) * 1.0)
093      
094     def popularity(self,train = None,test = None,k = 8,nitem = 10):
095     """
096     Get the popularity
097     the algorithm on page 44
098     """
099         train = train or self.traindata
100         test = test or self.testdata
101         item_popularity = dict()
102         for user ,items in train.items():
103             for item in items.keys():
104                 item_popularity.setdefault(item,0)
105                 item_popularity[item] += 1
106         ret = 0
107         = 0
108         for user in train.keys():
109             rank = self.recommend(user, train, k = k, nitem = nitem)
110         for item ,_ in rank.items():
111             ret += math.log(1+item_popularity[item])
112         += 1
113         return ret / (n * 1.0)
114          
115     def testRecommend():
116         ubcf = ItemBasedCF('u.data')
117         ubcf.readData()
118         ubcf.splitData(4,100)
119         ubcf.ItemSimilarity()
120         user = "345"
121         rank = ubcf.recommend(user,k = 3)
122         for i,rvi in rank.items():
123             items = ubcf.testdata.get(user,{})
124             record = items.get(i,0)
125             print "%5s: %.4f--%.4f" %(i,rvi,record)
126              
127     def testItemBasedCF():
128         cf = ItemBasedCF('u.data')
129         cf.ItemSimilarity()
130         print "%3s%20s%20s%20s%20s" % ('K',"recall",'precision','coverage','popularity')
131         for in [5,10,20,40,80,160]:
132             recall,precision = cf.recallAndPrecision( k = k)
133         coverage = cf.coverage(k = k)
134         popularity = cf.popularity(k = k)
135         print "%3d%19.3f%%%19.3f%%%19.3f%%%20.3f" % (k,recall * 100,precision * 100,coverage * 100,popularity)
136          
137 if __name__ == "__main__":
138 testItemBasedCF()

3 UserCF和ItemCF的综合比较:

UserCF给用户推荐那些和他有共同兴趣爱好的用户喜欢的物品,而ItemCF给用户推荐那些和他之前喜欢的物品类似的物品。从这个原理可以看到,UserCF的推荐结果着重于反映和用户兴趣相似的小群体的热点,而ItemCF的推荐结果着重于维系用户的历史兴趣。UserCF的推荐更社会化,反映了用户所在的小型兴趣群体中物品的热门程度,而ItemCF的推荐更加个性化,反映了用户自己的兴趣传承。同时,从技术上来说,UserCF需要维护一个用户相似度的矩阵,而ItemCF需要维护一个物品相似度矩阵。从存储的角度来说,如果用户很多,那么维护用户兴趣相似度矩阵需要很大的空间,同理,如果物品很多,维护物品相似度矩阵代价较大。

对于UserCF和ItemCF,我们采用http://www.grouplens.org/node/73 的数据集进行测试,使用准确率/召回率、覆盖率和流行度对实验结果进行评测。

对用户u推荐N个物品R(u),令用户u在测试集上喜欢的物品集合为T(u),则:

召回率描述有多少比例的用户-物品评分记录包含在最终的推荐列表中,而准确率描述最终的推荐列表中有多少比例是发生过的用户-物品评分记录。

覆盖率表示最终的推荐列表中包含多大比例的物品,如果所有的物品都被推荐给至少一个用户,那么覆盖率就是100%。

最后还需要评测推荐的新颖度,这里用推荐列表中物品的平均流行度度量推荐结果的新颖度,如果推荐出的物品都很热门,说明推荐的新颖度较低,否则说明推荐结果比较新颖。

图1 UserCF实验结果

图2 ItemCF实验结果

对于以上UserCF和ItemCF的实验结果可以看出,推荐系统的精度指标(准确率和召回率)并不和参数k成线性关系。推荐结果的精度对k也不是特别敏感,只要选在一定的区域内,就可以获得不错的精度。

对于覆盖率而言,k越大则推荐结果的覆盖率越低,覆盖率的降低是因为流行度的增加,随着流行度增加,推荐算法越来越倾向于推荐热门的物品,这是因为k决定了推荐算法在做推荐时参考多少和你兴趣相似的其他用户的兴趣,如果k越大,参考的人或者物品越多,结果就越来越趋近于全局热门的物品。

python实现itemCF and userCF的更多相关文章

  1. 推荐系统第2周--itemCF和userCF

    推荐系统分类 基于应用领域分类:电子商务推荐,社交好友推荐,搜索引擎推荐,信息内容推荐基于设计思想:基于协同过滤的推荐,基于内容的推荐,基于知识的推荐,混合推荐基于使用何种数据:基于用户行为数据的推荐 ...

  2. 推荐系统之隐语义模型(LFM)

    LFM(latent factor model)隐语义模型,这也是在推荐系统中应用相当普遍的一种模型.那这种模型跟ItemCF或UserCF的不同在于: 对于UserCF,我们可以先计算和目标用户兴趣 ...

  3. 推荐系统之隐语义模型LFM

    LFM(latent factor model)隐语义模型,这也是在推荐系统中应用相当普遍的一种模型.那这种模型跟ItemCF或UserCF的不同在于: 对于UserCF,我们可以先计算和目标用户兴趣 ...

  4. 推荐系统-协同过滤在Spark中的实现

    作者:vivo 互联网服务器团队-Tang Shutao 现如今推荐无处不在,例如抖音.淘宝.京东App均能见到推荐系统的身影,其背后涉及许多的技术.本文以经典的协同过滤为切入点,重点介绍了被工业界广 ...

  5. 推荐系统——online(上)

    框架介绍 上一篇从总体上介绍了推荐系统,推荐系统online和offline是两个组成部分,其中offline负责数据的收集,存储,统计,模型的训练等工作:online部分负责处理用户的请求,模型数据 ...

  6. Mahout介绍和简单应用

    Mahout学习(主要学习内容是Mahout中推荐部分的ItemCF.UserCF.Hadoop集群部署运行) 1.Mahout是什么? Mahout是一个算法库,集成了很多算法. Apache Ma ...

  7. 推荐系统第5周--- 基于内容的推荐,隐语义模型LFM

    基于内容的推荐

  8. 基于Spark机器学习和实时流计算的智能推荐系统

    概要: 随着电子商务的高速发展和普及应用,个性化推荐的推荐系统已成为一个重要研究领域. 个性化推荐算法是推荐系统中最核心的技术,在很大程度上决定了电子商务推荐系统性能的优劣,决定着是否能够推荐用户真正 ...

  9. 大数据学习路线copy自淘宝

    一.hadoop视频学习(入门到精通) 二.数据挖掘(入门到精通) 三.Hadoop学习路线 1.开发前期准备 首先,如果你没有Java和Linux基础,建议你先简单学一下这两门课程,此宝贝里面都为你 ...

随机推荐

  1. Tesseract ocr 3.02学习记录一

    光学字符识别(OCR,Optical Character Recognition)是指对文本资料进行扫描,然后对图像文件进行分析处理,获取文字及版面信息的过程.OCR技术非常专业,一般多是印刷.打印行 ...

  2. FireDAC 下的 Sqlite [1] - 前言

    很长时间没静下心来写博客了, 现在回来, 是 Delphi 不断地进步让我感动.振奋. Delphi XE5 并入了 FireDAC, 第一印象非常好, 恐怕 dbExpress 等等都要靠边站了. ...

  3. Dell H300/6i/6iR/H700/H800阵列卡配置(转)

    说明:其实Dell系列的阵列卡基本都是同一个套路和界面,包括操作步骤,不同的是不同的卡性能和支持Raid模式不一样而已. 名称解释: Disk Group:磁盘组,这里相当于是阵列,例如配置了一个RA ...

  4. HTML5中的跨文档消息传递

    跨文档消息传送(cross-document messaging),有时候也简称为XDM,指的是来自不同域的页面间传递消息.例如,www.w3cmm.com域中的一个页面与一个位于内嵌框架中的p2p. ...

  5. STM32的CRC32 软件实现代码

    对于STM32的32位CRC,如果假定它的一个主要目的是为了校验往内部FLASH存储数据的可靠性,那么(余数)初值是全1当然是比较合理的.由于STM32的32位CRC是纯32位,即每次必须输入32位的 ...

  6. CAS与LDAP集成

    参考文献: CAS集成ldap:https://wiki.jasig.org/display/CASUM/LDAP CAS集成restful api:https://wiki.jasig.org/di ...

  7. 《Go语言实战》摘录:7.3 并发模式 - work

    7.3 并发模式 - work

  8. effective C++ 读书笔记 条款08

    条款08  别让异常逃离析构函数: 假设在析构函数其中发生了异常,程序可能会过早结束或者导致不明白行为(异常从析构函数传播出去) 看代码: #include <iostream> usin ...

  9. Unity3D实践系列09, 物理引擎与碰撞检测

    在Unity3D中,一个物体通常包含一个Collider和一个Rigidbody.Collider是碰撞体,一个物体是Collider,才可以进行碰撞检测.Collider组件中的"Is T ...

  10. sql语句中having的作用是?

    HAVING对由sum或其它集合函数运算结果的输出进行限制.比如,我们可能只希望看到Store_Information数据表中销售总额超过1500美圆的商店的信息,这时我们就需要使用HAVING从句. ...