协作型推荐
一个协作型过滤算法是对一大群人进行搜索,并从中找出与我们品味相近的小群人。算法会对这些人所偏爱的其他内容进行考察,并将他们组合起来构造出一个经过排名的推荐列表。
搜集偏好
我们通过采用嵌套的字典的方法来表达不同人及其偏好的方法。
我们建立一个数据集,命名为recommendations.py 采用1到5的评分,来体现包括本人在内的每位影评者对某给定影片的喜爱程度。
from recommendations import critics
critics['Lisa Rose']['Lady in the Water']
#输出Lisa Rose对Lady in the water这部电影的评分。
寻找相近的用户
在搜集完人们的偏好后,即建立数据集后,我们需要一种方法来确定人民在品味中的相似程度。我们可以将每个人与所有其他人进行对比,并计算他们的相似度评价值。
欧几里得距离评价
1/(1+sqrt(pow(x1-x2,2)+pow(y1-y2,2)))
上述值越大,表示越相似。
prefs表示数据集名称;person1表示数据集中的key;item表示下一级电影名称;prefs[preson1][item]表示分数。
from math import sqrt
#返回一个有关person1与person2的基于距离的相似度评价
def sim_distance(prefs,person1,person2):
si={}
for item in prefs[person1]:
if item in prefs[person2]: #表示两个人都有电影重合
si[item]=1 #item是key;1是value
if len(si)==0:
return 0
#计算两个人中重合的电影中评分的差值的平方和
sum_of_squares=sum([pow(prefs[person1][item]-prefs[preson2][item],2) for item in prefs[person1] if item in prefs[person2]])
return 1/(sqrt(sum_of_squares)+1)
reload(recommendations)
recommendations.sim_distance(recommendations.critics,'Lisa Rose','Gene Seymour')
#输出相似度数字
皮尔逊相关度评价
该相关系数是判断两组数据与某一直线拟合程度的一种度量,在数据不是很规范的情况下,会倾向给出更好的结果。
它可修正夸大分值的情况。
from math import sqrt
#返回一个有关person1与person2的基于距离的相似度评价
def sim_person(prefs,p1,p2):
si={}
for it in prefs[p1]:
if it in prefs[p2]: #表示两个人都有电影重合
si[it]=1 #item是key;1是value
if len(si)==0:
return 0
#对所有偏好进行求和
sum1=sum([prefs[p1][it] for it in si])
sum2=sum([prefs[p2][it] for it in si])
#求平方和
sum1sq=sum([pow(prefs[p1][it],2) for it in si])
sum2sq=sum([pow(prefs[p2][it],2) for it in si])
#求乘积和
psum=sum([prefs[p1][it]*prefs[p2][it] for it in si])
#计算皮尔逊评价值
num=psum-(sum1*sum2/n)
den=sqrt((sum1sq-pow(sum1,2)/n)*(sum2sq-pow(sum2,2)/n))
if den==0:
return 0
r = num/den
return r
为评论者打分
我们将下列函数加入recommendation.py中,以得到一个人员的有序列表,这些人与某个指定人员具有相似的品味。
prefs为数据集;person为某个指定人员;similarity为某个相似度函数
def topmatches(prefs,person,n=5,similarity=sim_person):
#将指定人员与数据中除自己外的所有人员一一比较,记录相似度值。
scores = [(similarity(prefs[person],other),other) for other in prefs for other in prefs if other != person]
#评价最高者排在最前面
scores.sort()
scores.reverse()
return scores[0:n] #输出前三个数
#topmatches为函数;critics为数据集;recommendations.py为函数
reload(recommendations)
recommendations.topmatches(recommendations.critics,'Toby',n=3)
输出的是与目标人员兴趣最相近的其他人员。
推荐物品
如果我们利用为评论者打分算法,得到口味最相近的其他人,在他的电影清单中选择,未免有点随意。本部分之间推荐与目标人员兴趣匹配的最佳电影。输出的是电影。 我们利用数据集,得到所有其他评论者与指定人员的相似度之后,再用相似度乘以他们对每部影片的评分,再把加权后的每部影片相加,除以相似度之和,对最终数据从高到低排序,得到最终的推荐影片排序。
与topmatches对比,输出不同。
#利用所有其他人评价值的加权平均,为某人提供建议
def getrecommendations(prefs,person,similarity=sim_person)
totals={}#为每部影片的加权后的总和
simsums={}#为其他人相似度的总和
#prefs为数据集
for other in prefs:
#不和自己做比较,person为指定人员
if other==person:continue
sim=similarity(prefs,person,other)#sim为相似度
#忽略评价值为零或小于零的情况
if sim<=0:continue
#item为电影
for item in prefs[other]:
if item not in prefs[person] or prefs[person][item]==0:
totals.setdefault(item,0)
total[item]+=prefs[other][item]*sim
simsums.setdefault(item,0)
simsums[item]+=sim
ranking=[(total/simsums[item],item) for item,total in totals.items()]
ranking.sort()
ranking.reverse()
return ranking
reload(recommendations)
recommendations.getcommendations(recommendations.critics,'Toby')
输出的是推荐的相似度高的电影。
匹配商品(人与物交换)
假如我们想了解哪些产品是相近的呢?在这种情况下,我们可以通过哪些人喜欢某一特定物品,以及这些喜欢哪些其他物品来决定相似度。即我们把之前的例子,人与物品互换即可。
人与物品互换
def transformprefs(prefs): #prefs为数据集
result={} #result为与prefs类似的数据集
for person in prefs:
for item in prefs[person]:
result.setdefault(item,{})
result[item][person]=prefs[person][item]
return result#新的数据集
获取与《superman returns》最类似的电影
reload(recommendations)
#movies为新的数据集
movies=recomms.transformprefs(recommendations.critics)
recommendations.topmatches(movies,'superman returns')
我们还可以为该影片推荐评论者,或许我们考虑要求某人参加该电影的首映礼。
reload(recommendations)
#movies为新的数据集
movies=recomms.transformprefs(recommendations.critics)
recommendations.getrecommendations(movies,'superman returns')
应用
在线零售商可以收集{person:{item1,item2}},将商品和人对调,可以帮助他们找到购买某个商品的潜在用户。此外,在专门推荐链接的网站上,可以确保新出现的链接,能够被那些最有可能对它产生兴趣的用户找到。
构建一个基于del.icio.us的链接推荐系统
本节将介绍,如何从最受欢迎的在线书签网站上获取数据,如何利用这些数据查找相近的用户,并向他们推荐一起未曾看过的链接。
但是这个API已经失效了!!
故放弃
使用MOVIELENS数据集做推荐
下载MovieLens的地址:http://grouplens.org/datasets/movielens/
数据集中的格式为:用户ID、影片ID、用户对该片的评分、评价时间
加载数据:
def loadMovieLensTrain(filename='u1.base'):
str1 ='./ml-100k/'
#加载数据
prefs={}
for line in open(str1+filename,'r'):
(user,movieid,rating,ts)=line.split('\t')
prefs.setdefault(user,{})
prefs[user][movieid]=float(rating)
return prefs
def loadMovieLensTest(filename='u1.test'):
str1 ='./ml-100k/'
#加载数据
prefs={}
for line in open(str1+filename,'r'):
(user,movieid,rating,ts)=line.split('\t')
prefs.setdefault(user,{})
prefs[user][movieid]=float(rating)
return prefs
if __name__=="__main__":
print ("""这个部分可以进行上面2个函数测试""")
trainDict= loadMovieLensTrain()
testDict = loadMovieLensTest()
print (len(trainDict))
print (len(testDict))
print ("""测试通过""")
在该数据集中,建立字典,key为用户,value为电影和评分,与之前的critics数据集类似。
测试结果如下:
2为用户ID;306为某个电影ID;4.0为该电影的评分
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UI7ojT4H-1582534683983)(FECD665D69B741648ECD1B0B35D71D16)]
为用户28号推荐电影前20部
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RupEiWAl-1582534683985)(FF37059EE8AB4593901CACED812E8747)]