py2.7 《集体智慧编程》chapter2:提供推荐

时间:2022-12-25 12:32:13

一、搜集偏好(构造数据集):

#使用字典嵌套构造数据集:一个涉及影评者及其对几部影片评分情况的字典
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}}
#该字典使用了1~5的评分等级来代表用户对物品的喜爱程度

测试样例:

from recommendations import critics
print critics['Lisa Rose']['Lady in the Water']
print critics['Toby']

效果:

2.5
{'Snakes on a Plane': 4.5, 'Superman Returns': 4.0, 'You, Me and Dupree': 1.0}


二、寻找相近的用户:

1、欧几里得距离评价

解释:两个人在“偏好空间”中的距离越近,他们的兴趣偏好就越相似。但是当两个人中有一个人比较极端,或者严格每次比另外一个人大,得到的结果偏低,其实并不准确

#欧几里得距离评价
from math import *
def sim_distance(prefs , person1,person2): #返回p1和p2基于距离的相似度评价
#得到一个shared_items的列表
si = {}
for item in prefs[person1]:
if item in prefs[person2]:
si[item] = 1
if len(si) ==0 : return 0 #如果两者没有共同之处,返回0

#计算所有差值的平方和
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)) #加1防止遇到除以0,被1除将相似度局限于0~1之间

测试:

import recommendations
print recommendations.sim_distance(recommendations.critics , 'Lisa Rose' , 'Gene Seymour')
输出:

0.294298055086

2、皮尔逊相关系数评价

解释:通过利用协方差的特性来描述两个事件是否相关,以及通过模拟皮尔逊相关系数的公式。优点是不受极限情况干扰

#皮尔逊相关系数:实质是协方差除以p1,p2标准差乘积
def sim_pearson(prefs , p1 , p2):
#得到双方都曾经评价过的物品列表
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]) #对于求期望而言,他们概率不是1就是0
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][ti]*prefs[p2][ti] for ti 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
测试:

import recommendations
print recommendations.sim_pearson(recommendations.critics, 'Lisa Rose', 'Gene Seymour')

输出:

0.396059017191

三、为评论者打分:

在上面的数据集我们已经知道了每个人对不同物品之间的打分,以及使用两种计算相似度的方法去计算两个人之间的相似度,这里我们整合起来给出已知的一个人,求出另外其他人中与他评论最相似的n个人(n为降序排列,默认为5)

#为评论者打分
#从反映偏好的字典里返回最佳匹配者
#让返回结果的个数和相似度函数均为可选参数
def topMatches(prefs,person,n=5,similarity=sim_pearson): #数据集,需要观察的人,默认降序的5个人,默认使用皮尔逊相关系数
scores = [(similarity(prefs,person,other),other)
for other in prefs if other!= person] #在列表中找到不是自己的人进行similarity方法
#对列表进行排序,评价最高的排在前面
scores.sort()
scores.reverse()
return scores[0:n]
测试

import recommendations
print recommendations.topMatches(recommendations.critics,'Toby',n=3)
结果:

[(0.9912407071619299, 'Lisa Rose'), (0.9244734516419049, 'Mick LaSalle'), (0.8934051474415647, 'Claudia Puig')]

四、推荐物品:

这部分我们想得到一份影片的推荐,但是存在:1.别人没评价我们很喜欢 2.热衷某类影片的古怪评论者,但大部分人都不喜欢的影片从而干扰推荐

因此对所有影片进行加权评价来打分。我们先经过评价结果得到相似度,在对相似度乘以他们的评价值,得到加权后的评价值

#利用所有他人评价值的加权平均,为某人提供建议
def getReconmmendations(prefs,person,similarity=sim_pearson):
total = {}
simSums = {}
for other in prefs:#循环查找prefs字典的其他人,与参数person得到影片相似度
#不和自己比较
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:
#相似度*评价值
total.setdefault(item,0)#setdefault方法:如果键不存在则设为默认值0
total[item]+=prefs[other][item]*sim #每一项的评价值*相似度并且累加
#相似度之和
simSums.setdefault(item,0)
simSums[item]+=sim
#建立一个归一化的表
rankings = [(total/simSums[item],item) for item,total in total.items()]
#返回排序列表
rankings.sort()
rankings.reverse()
return rankings

测试:

from recommendations import *
print getReconmmendations(critics,'Toby')
效果:

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

在这里采用的是皮尔逊方法,用欧几里得评价也是可以的