协同过滤首次出现在《Using collaborative filtering to weave an information tapestry》论文中。他设计了一个名叫Tapesrty的系统,该系统允许人们根据自己对文档感兴趣的程度为其添加标注,并利用这一信息为他人进行文档过滤。
以字典格式存储偏好:{user:{‘movie’:socre}}
尽管可以将相当数量人员的偏好信息存储于字典中,但对于一个规模巨大的数据集,还是存在数据库比较方便。
此处采用了欧几里得距离和皮尔逊相关系数。皮尔逊相关系数可以修正“夸大分值”,即如果A倾向于给出更高的分值,B倾向于给出更低的分值,他们对于movie1和movie2的偏好相同,此时用欧式距离,A和B的偏好相似会被低估。
编程tips:
点击链接可以了解到不同的距离度量算法
def getRecommendations(prefs,person,similarity=sim_pearson):
totals={}
simSums={}
for other in prefs:
if other==person:continue
sim=similarity(prefs,person,other)
#忽略相关系数小于等于0的情况
if sim<=0:continue
for item in prefs[other]:
#只对自己还未曾看过的影片进行评价
if item not in prefs[person] or prefs[person][item]==0:
#相似度*评价值
totals.setdefault(item,0)#插入键值对并输出值;这个函数如果有值的时候不会再写入
totals[item]+=prefs[other][item]*sim
#相似度之和
simSums.setdefault(item,0)
simSums[item]+=sim
#建立一个归一化的列表
rankings=[(total/simSums[item],item) for item,total in totals.items()]
#返回经过排序的列表
rankings.sort(reverse=True)
return rankings
注意setdefault函数,非常强大,可以用于实现设定字典的层数。如果不这么做的话,默认键值对的值只能是单层的,不能写入字典。
def transformPrefs(prefs):
result={}
for person in prefs:
for item in prefs[person]:
result.setdefault(item,{})
#将物品和人员对调
result[item][person]=prefs[person][item]
return result
#基于物品的协作型过滤(item-based collaborative filtering)
#构建物品比较数据集
def calculateSimilarItems(prefs,n=10):
#建立字典,以给出与这些物品最为相近的其他所有物品
result={}
#以物品为中心对偏好矩阵实施倒置处理
itemPrefs=transformPrefs(prefs)
c=0
for item in itemPrefs:
#创建大数据集更新状态变量
c+=1
if c%100==0:print('%d /%d'%(c,len(itemPrefs)))
#寻找最为相近的物品
scores=topMatches(itemPrefs,item,n=n,similarity=sim_distance)
result[item]=scores
return result
#为某人提供基于物品的推荐
#例如,A对电影1的评价是4分,电影1和电影2的相似度是0.5,计算加权得分就是0. 5*4
def getRecommendedItems(prefs,itemMatch,user):
userRatings=prefs[user]
scores={}
totalSim={}
#循环遍历由当前用户评分的物品
for (item,rating) in userRatings.items():
#循环遍历与当前物品相近的物品
for (similarity,item2) in itemMatch[item]:
#如果该用户已经对当前物品做过评价,则将其忽略
if item2 in userRatings: continue
#评价值与相似度的加权之和
scores.setdefault(item2,0)
scores[item2]+=similarity*rating
#全部相似度之和
totalSim.setdefault(item2,0)
totalSim[item2]+=similarity
#将每个合计值除以加权和,求出平均值
rankings=[(score/totalSim[item],item) for item,score in scores.items()]
#按最高值到最低值的顺序,返回评分结果
rankings.sort(reverse=True)
return rankings
##在调用getRecommendedItems时,我们不必再为所有其他评论者计算相似度评价值,因为物品相似度数据集已经实现构造好了
下载数据后,首先观察原csv文件的数据结构。这么做的目的是:
编程tips:
islice(iterable,start,stop,step)
;,
进行分隔即可,不需要\t
或者\n
。#使用movielens数据集
def loadMovieLens(path=''):
#获取影片标题
movies={}
for line in islice(open(path+'movies.csv'),1,None):
(id,title)=line.split(',')[0:2]
movies[id]=title
prefs={}
for line in islice(open(path+'ratings.csv'),1,None):
(user,movieid,rating,ts)=line.split(',')
prefs.setdefault(user,{})#设置prefs的参数为字典嵌套字典
prefs[user][movies[movieid]]=float(rating)
return prefs
the advantages of item_based collaborative filtering:
the advantages of user_based collaborative filtering:
提示:要了解更多有关算法在执行效率上的差异,可以参考《基于物品的协作型过滤推荐算法》(Item_based Collaborative Flitering Recommendation Algorithms)