集体智慧编程学习笔记——提供推荐(一)
协作型过滤
一个协作型过滤 的通常做法是对一大群人进行搜索,并从中找到与我们品味相近的一小群人。算法会对这些人偏爱的其他内容进行考察,并将它们组合起来构造出一个经过排名的推荐列表。有许多不同的方法可以帮助我们确定哪些人与自己品位接近,并将他们的选择组合成列表。
搜集偏好(构造数据集)
使用嵌套的字典,写一个py文件
- 将使用交互方式使用python ,因此应该先将这个py文件保存起来,便于python的交互解释程序能够读取到它;
#一个涉及影评者及其对几部影片评分情况的字典
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},
'xiaoYu': {'Lady in the Water': 2.0, 'Snakes on a Plane': 3.0, 'Just My Luck': 2.5, 'Superman Returns': 3.0, 'You, Me and Dupree': 2.0, 'The Night Listener': 2.5}
}
相近的用户
搜集完人们的偏好数据后,需要有一种方法来确定人们在品味方面的相似程度。为此,可以将每个人与所有其它人进行对比,并计算他们的相似度评价值
介绍两套计算相似度评价值的体系:
欧几里得距离
皮尔逊相关度
欧几里得距离评价
以经过人们一致评价的物体为坐标轴,将参与评价的人绘制到图上,考察彼此间的距离远近。
处于偏好空间中的人们
两人在偏好空间中的距离越近,他们的兴趣偏好就越相似。
求两人在坐标平面的距离:
from math import sqrt
print(sqrt(pow(4.5-4, 2)+pow(1-2, 2)))
需要一个偏好函数:偏好越相近的情况给出越大的值:
1
x
2
+
y
2
+
1
\frac{1}{\sqrt {x^2+y^2}+1}
x2+y2+11
加一可以避免被0整除的错误。这一新的函数返回介于0-1之间的值,返回1 表明两人具有一样的偏好
构造计算相似度的函数sim_distance:
#返回一个有关person1和person2的基于距离的相似度的评价
def sim_distance(prefs, person1, person2):
#得到shared_items的列表
si={}
for item in prefs[person1]:
if item in prefs[preson2]:
si[item]=1
#如果两者没有共同之处,则返回0
if len(si)==0: return 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/sqrt(sum_of_squares)
可以通过以下方式获取两个人的欧几里得距离:
import recommendations
x=recommendations.sim_distance(recommendations.critics, 'Lisa Rose', 'Gene Seymour')
print(x)
皮尔逊相关度评价
更复杂的方法判断人们兴趣的相似度:皮尔逊相关系数
该相关系数是判断两组数据与某一直线拟合程度 的一种度量,对应的公式比欧几里得距离评价的计算公式要复杂。
它在数据不是很规范(如:影评者对影片的评价总是相对于平均水平偏离很大的时候),会倾向于给出更好的结果。
通过绘制一条最佳拟合线尽可能地靠近图上所有的坐标点。如果两位评论者对所有影片的评分情况都相同,那么这条直线将成为对角线,并与图上所有的坐标点都相交,从而得到一个结果为1的理想相关度评价。
对于下图,由于评论者对部分影片的评分不尽相同,因而相关系数大约为0.4左右
下图是一个相关度更高的例子,皮尔逊系数为0.75
该算法的好处:即使一个人一直倾向于给更低的分数(更加严格),直线也能拟合,表示两人的偏好相同的程度。
皮尔逊相关度评价算法:
- 找出两位评论者都曾评价过的物品
- 计算两者的评分总和与平方和
- 求得评分的乘积之和
- 利用这些计算结果计算出皮尔逊相关系数
写一个函数sim_pearson计算相关系数
#返回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 len(si)==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
该函数返回一个介于-1 到 1 之间的数值。值为1 表示两个人对每一样物品均有完全一致的评价
与距离。