1.获取数据:
这儿有一个开源的数据集grouplens
以及集体智慧编程上的数据集。以下是集体智慧编程上的一个关于电影评价的数据集
critices={
'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, 'You,Me and Dupree': 3.5,
'The Night Listener': 3.0
},
'Michael Phillips':{
'Lady in the Water': 2.5, 'Snakes on a plane': 3.0,
'Superman Returns': 3.5, 'The Night Listener': 3.0
},
'Claudia puig':{
'Snakes on a plane': 3.5, 'Just My Luck': 3.0, 'Superman Returns': 4.0,
'You,Me and Dupree': 2.5,'The Night Listener': 4.5
},
'Mick LaSalle':{
'Lady in the Water': 3.0, 'Snakes on a plane': 4.0,
'Just My Luck': 2.0, 'Superman Returns': 3.0, 'You,Me and Dupree': 2.0,
'The Night Listener': 3.0
},
'Jack Matthews':{
'Lady in the Water': 3.0, 'Snakes on a plane': 4.0,
'Superman Returns': 5.0, 'You,Me and Dupree': 3.5,
'The Night Listener': 3.0
},
'Toby':{
'Snakes on a plane': 4.5,
'Superman Returns': 4.0, 'You,Me and Dupree': 1.0
},
}
2.寻找相似度的算法:
①.欧几里得距离评价
#欧几里得距离
#prefs->数据集
#person1,person2->两个不同的用户,
def sim_distance(prefs,person1,person2):
si={}
for item in prefs[person1]:
if item in prefs[person2]:
si[item]=1
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/(1+sqrt(sum_of_squares))
②.皮尔逊相似度算法:
def sim_person(prefs,p1,p2):
si={}
for item in prefs[p1]:
if item in prefs[p2]:
si[item]=1
n=len(si)
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
③.Tanimoto相关度评价值
def sim_Tanimoto(prefs,person1,person2):
sim_and=[]
for item in prefs[person1]:
if item in prefs[person2]:
sim_and.append(item)
return (len(sim_and)*1.0/(len(prefs[person1])+len(prefs[person2])-len(sim_and)))
关于这三个算法的分析:
Tanimoto只针对于结果是二值(0,1)的相关评价,如对电影评价只有觉得好看和不好看两种,这样的情况可以用Tanimoto算法。
对于欧几里得距离算法和皮尔逊算法,在对于数据集不是很规范的时候,(如影评者的评价相对于平均水平偏离大的时候)使用皮尔逊算法会得到更好的结果。
3.以上算法都是针对两个人的相关度算法,可以使用求出与某一用户相似度相近的前几个用户的函数:
#返回与person的最佳匹配者集合
#prefs->数据集,person->某一用户,n->求出前n个相似用户,similarity->通过哪种求相似度的算法
def topMatches(prefs,person,n=5,similarity=sim_person):
scores=[(similarity(prefs,person,other),other) for other in prefs if other!=person]
scores.sort()
scores.reverse()
return scores[0:n]
4.推荐物品:
#利用所有他人的评价值得加权平均,为某人提供建议(具体不理解算法的,参考集体智慧编程)
def geetRecommendations(prefs,person,similarity=sim_person):
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)
totals[item]+=sim*prefs[other][item]
simSums.setdefault(item,0)
simSums[item]+=sim
#建立一个归一化的列表
ranking=[(total/simSums[item],item) for item,total in totals.items()]
ranking.sort()
ranking.reverse()
return ranking
5.物品之间的相似:
与人与人之间相似类似,这儿只需要将数据集中的人和物品转换一下位置即可。
#转换人和物
def transformPrefs(prefs):
result={}
for person in prefs:
for item in prefs[person]:
result.setdefault(item,{})
result[item][person]=prefs[person][item]
return result
转换之后类似这样的
'Lady in the Water': {'Lisa Rose': 2.5, 'Jack Matthews'
: 3.0, 'Michael Phillips': 2.5, 'Gene Seymour': 3.0, 'Mick LaSalle': 3.0}
6.以上的算法都是基于用户的协作型过滤,接下来就是基于物品的协作型过滤,对于稀疏数据集基于物品的方法优于基于用户,对于密集数据集,两者效果一样。
#生成与每个物品相似度的数据集
def calculateSimlarItems(prefs,n=10):
result={}
itemprefs=transformPrefs(prefs)
c=0
for item in itemprefs:
c+=1
if c%100==0:
print '%d / %d '%(c,len(itemprefs))
score=topMatches(itemprefs,item,n=n,similarity=sim_distance)
result[item]=score
return result
#通过物品对某个人获取推荐
#因为预先处理了物品相似度,所以这儿的推荐过程效率很快,预先处理的过程可以在空闲的时候做。
#这儿的itemMatch是每个物品相似度的数据集,user是推荐用户
def getRecommendedItems(prefs,itemMatch,user):
userRatings=prefs[user]
scores={}
totalSim={}
for (item,rating) in userRatings.items():
for (similarity,item2) in itemMatch[item]:
if item2 in userRatings:
continue
scores.setdefault(item2,0)
scores[item2]+=rating*similarity
totalSim.setdefault(item2,0)
totalSim[item2]+=similarity
rankings=[(score/totalSim[item],item) for item,score in scores.items()]
rankings.sort()
rankings.reverse()
return rankings