集体智慧编程_第二章提供推荐

本文介绍了协作型推荐系统的原理和实现方法,包括搜集用户偏好、计算用户之间的相似度(如欧几里得距离和皮尔逊相关度)、为评论者打分、推荐物品和匹配商品。通过实际案例展示了如何使用Python实现推荐系统,如使用MOVIELENS数据集。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

协作型推荐

一个协作型过滤算法是对一大群人进行搜索,并从中找出与我们品味相近的小群人。算法会对这些人所偏爱的其他内容进行考察,并将他们组合起来构造出一个经过排名的推荐列表。

搜集偏好

我们通过采用嵌套的字典的方法来表达不同人及其偏好的方法。

我们建立一个数据集,命名为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)]