协同过滤一般是在海量的用户中发掘出一小部分和你品位比较类似的,在协同过滤中,这些用户成为邻居,然后根据他们喜欢的其他东西组织成一个排序的目录推荐给你。
要实现协同过滤,需要以下几个步骤:
搜集偏好
寻找相近用户
推荐物品
首先,我们要寻找一种表达不同人及其偏好的方法。这里我们用python的嵌套字典来实现。
#将id替换为电影名构造数据集defloadMovieLens(path='data'):#Getmovietitlesmovies={}forlineinopen(path+'/u.item'):(id,title)=line.split('|')[0:2]movies[id]=title#Loaddataprefs={}forlineinopen(path+'/u.data'):(user,movieid,rating,ts)=line.split('\t')prefs.setdefault(user,{})prefs[user][movies[movieid]]=float(rating)returnprefs根据上面两个函数中的一种,到此我们的用户数据集已经构造好了,由于数据量不是非常大,暂时放在内存中即可。由于以上数据集比较抽象,不方便讲解,至此我们定义一个简单的数据集来讲解一些例子,一个简单的嵌套字典:
欧几里得距离(euclideanmetric)(也称欧式距离)是一个通常采用的距离定义,指在m维空间中两个点之间的真实距离,或者向量的自然长度(即该点到原点的距离)。在二维和三维空间中的欧氏距离就是两点之间的实际距离。
计算上图中Toby和MickLaSalle的相似度:
frommathimportsqrtsqrt(pow(4.5-4,2)+pow(1-2,2))1.118033988749895
上面的式子计算出了实际距离值,但在实际应用中,我们希望相似度越大返回的值越大,并且控制在0~1之间的值。为此,我们可以取函数值加1的倒数(加1是为了防止除0的情况):
1/(1+sqrt(pow(4.5-4,2)+pow(1-2,2)))0.4721359549995794
接下来我们就可以封装一个基于欧几里得距离的相似度评价,具体python实现如下:
#欧几里得距离defsim_distance(prefs,person1,person2):si={}foritemIdinprefs[person1]:ifitemIdinprefs[person2]:si[itemId]=1#nosameitemiflen(si)==0:return0sum_of_squares=0.0#计算距离sum_of_squares=sum([pow(prefs[person1][item]-prefs[person2][item],2)foriteminsi])return1/(1+sqrt(sum_of_squares))基于测试数据集critics,则可以计算两个人的相似度值为:
sim_distance(critics,'Toby','MickLaSalle')0.307692307692
python代码实现:
recommendations.sim_pearson(recommendations.critics,'GeneSeymour','LisaRose')
同样,先构造数据集,即以物品为key的字典,格式为{电影:{用户:评分,用户:评分}}
#基于物品的列表deftransformPrefs(prefs):itemList={}forpersoninprefs:foriteminprefs[person]:ifnotitemList.has_key(item):itemList[item]={}#result.setdefault(item,{})itemList[item][person]=prefs[person][item]returnitemList计算物品间的相似度,物品间相似的变化不会像人那么频繁,所以我们可以构造物品间相似的集合,存成文件重复利用: