提供推荐——协作型过滤

一、协作型过滤

一个协作型过滤算法通常的做法是对一大羣人进行搜索,并从中找出与我们品味相近的一羣人。然后对这些人的偏好内容进行考查,并将它们组合起来构造出一个经过排名的推荐列表。

  1. 蒐集偏好
  2. 寻找相近的用户
    • 欧几里得距离评价
    • 皮尔逊相关度评价
  3. 为相近用户打分排序
  4. 推荐物品
  5. 推荐结果

1.蒐集偏好

# 不同用户对电影的评分字典
critics={'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}}

2.寻找相近的用户

寻找相近用户可以使用不同的相似度评价值体系:这里介绍两种:欧几里得距离和皮尔逊相关度。
欧几里得距离:它是基于距离的相似度评价
皮尔逊相关度:用来判断两组数据与某一直线拟合程度的一种度量。它更适合于当两名用户虽然对电影有相同的爱好,但是用户1评分更严苛,而用户2更宽松,那么用欧几里得距离来计算两者相似度就会有偏差,但是皮尔逊相关度,会更关注两者的趋势。

#寻找近似用户,计算两个用户的相似度(欧几里得距离)

def sim_distance(prefs,person1,person2):  #prefs是指存储所有用户评分的字典
# 得到shared_items两个用户都给出评分的电影列表
si ={}
for item in prefs[person1]:
    if item in prefs[person2]:
        si[item] =1

if len(si) == 0:
    return 0 #此时两个用户没有共同评分的影片,相似度为0
else:
    sum_of_squares =sum([pow(prefs[person1][item]-prefs[person2][item],2) for item in prefs[person1] if item in prefs[person2]])
    return 1/(1+sqrt(sum_of_squares)) #这个是转化为直接理解的相似度数值,sum_of_squares越大,相似度越小

# 寻找近似用户,计算两个用户的相似度(皮尔逊相关度)

def sim_pearson(prefs,p1,p2):
    # 得到shared_items两个用户都给出评分的电影列表
    si={}
    for item in prefs[p1]:
        if item in prefs[p2]:
            si[item] =1
    # 得到列表元素的个数
    n =len(si)
    # 如果两个人没有共同之处,则返回1
    if n==0:
        return 1

    # 对所有偏好求和
    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

3.为相近用户打分排序

# 计算其他用户与某名用户的相似度并根据相似度进行排序

def topMatchers(prefs,person,n,similarity=sim_pearson): #similarity指定计算相似度的算法
    scores =[(similarity(prefs,person,other),other) for other in prefs if other!=person]
    scores.sort()
    scores.reverse()
    return scores[0:n]
    

4.推荐物品

此时,我们可以单纯的从相近用户中没有观看过的电影列表中直接进行推荐,但是这种做法太过随意。我们想要针对一部电影,从其他用户与目标用户的相似度以及他们对该部的电影评分求加权平均值,这也是所预期的目标用户会对某部电影的评分值。根据评分值的大小对推荐列表进行排序。

def getRecommendations(prefs,person,similarity=sim_pearson):
totals ={} # 用来存储 相似度*每个用户评分 的和
simSums = {} # 用来存储 相似度 的和

for other in prefs:
    # 不和自己比较
    if other ==person :continue
    sim = similarity(prefs,person,other)
    # 忽略相似度为零或小于零的情况
    if sim<=0: continue
    for item in prefs[other]: # 对某个其他用户看过的电影进行迭代
        # 只对自己还未曾看过的影片进行评价
        if item not in prefs[person] or prefs[person][item] ==0:
            # 相似度*评价值
            totals.setdefault(item,0) # if key is in the dictionary ,return its value,if not,insert key wit a value of default
            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()
rankings.reverse()
return rankings

5.推荐结果

#欧几里得距离评价:

[(3.457128694491423, 'The Night Listener'), (2.7785840038149243, 'Lady in the Water'), (2.422482042361916, 'Just My Luck')]

皮尔逊相关度评价:

[(3.3477895267131013, 'The Night Listener'), (2.832549918264162, 'Lady in the Water'), (2.5309807037655645, 'Just My Luck')]
点赞