推荐算法实战

推荐算法实战

本文基于《集体智慧编程》的第二章,提供推荐的一篇文章,不得不说,这本书真的很好,在写这一篇文章的时候,我已经看到优化那一章,单单从优化角度来讲,特别清晰,从最简单的随机优化开始,讲述了爬山法,到模拟退火算法,到最为流行的遗传算法,感觉很有必要将学习的过程记录下来,便于我,或初学者来进入机器学习领域。

1.协作性过滤

    随着社会的发展,根据群体偏好来为人们提供推荐显得越来越重要,比如,在线购物的商品推荐、热门网站的推荐,以及帮助人们寻找音乐和影片的应用。协作性过滤的思想就是集合大家的智慧,来为某人进行推荐。让我们实战实现这样的一种应用。

首先收集偏好,这篇博客代码基于python,在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}}
2.寻找相近的用户:

   收集完人们的偏好之后,我们需要一种方法来确定人们在品味方面的相似度。为此,我们可以将每个人与其他人进行对比,并计算他们的相似评价值。有多种评价方式,这篇博客介绍欧几里得距离皮尔逊相关系数

欧几里得距离评价:

     

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))

皮尔逊相关系数:

数学公式如下,字迹有点丑。。。

推荐算法实战_第1张图片

代码如下:

def sim_pearson(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
	return num/den
3.为评论者打分:

    既然我们已经有了对两个人的进行比较的函数,下面我们就可以编写函数,根据指定人员对每个人打分,并找出最接近的结果,以得到一个人员的有序列表,代码如下:

def topMatches(prefs,pearon,n=5,similarity=sim_pearson):
	scores = [(similarity(prefs,pearon,other),other) for other in prefs if other!=pearon]
	scores.sort()
	scores.reverse()
	return scores[0:n]

4.推荐物品

    终于到最后一步了,找到一位趣味相投的影评者很不错,但我们需要一份影片的推荐,从相似的人找一部自己寒没有看过的影片。代码如下:

def getRecommendations(prefs,person,similarity=sim_pearson):
	total = {}
	simSum = {}
	
	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:
				total.setdefault(item,0)
				total[item]+=prefs[other][item]*sim
				
				simSum.setdefault(item,0)
				simSum[item]+=sim
	rankings = [(total/simSum[item],item) for item,total in total.items()]
	rankings.sort()
	rankings.reverse()
	return rankings

这样,我们不仅得到了一个经过排名的影片列表,而且还推测出了自己对每部电影的评价情况。根据这份结果,我们决定自己究竟要不要观看其中的某部电影。到这里,我们已经学会了基于用户的协同过滤算法。



匹配商品:

    到现在为止,我们已经知道了如何为指定人员寻找品味相近者,以及如何向其推荐商品的方法。但是假如我们想了解哪些商品是彼此相近的,在这种情况下,我们可以通过查看那些人喜欢某一特定物品。在这种情况下,我们只需要将人员与物品对换即可:

<span style="font-size:12px;">def transformPrefs(prefs):
	result = {}
	for person in prefs:
		for item in prefs[person]:
			result.setdefault(item,{})
			result[item][person]=prefs[person][item]
	return result</span>
基于物品的过滤:

    到现在为止,我们已经完成了一种推荐算法,但对于像Amazon这样的有着上百万客户和商人的大型网站而言,讲一个用户和所有的其他用户进行比较,然后再每位用户评过分的商品进行比较,其速度是无法忍受的。这样,我们要介绍另一种可供选择的算法成为基于物品的协作型过滤

    总体思路为为每件物品预先计算好最为相近的其他物品,然后,当我们想为某位用户提供推荐时,就可以查看他曾经评价过的物品,从中选择排位靠前者,再构造出一个加权列表,其中包含了最为相近的其他物品,因为物品见得比较不会像用户间的比较那么频繁。

1.构造物品比较数据集

    计算物品之间的相似程度:

<span style="font-size:12px;">def calculateSimilarItems(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
</span>
2.获得推荐:

这段解释比较繁琐,就直接上原图解释吧:推荐算法实战_第2张图片


代码如下:

<span style="font-size:12px;">def getRecommendItems(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]+=similarity*rating
			totalSim.setdefault(item2,0)
			totalSim[item2]+=similarity
	
	
	rankings=[(score/totalSim[item],item) for item,score in scores.items()]
	
	rankings.sort()
	rankings.reverse()
	return rankings</span>
到现在为止,已经成功的实现了推荐算法原理解释。让我们现在使用真实数据集来实战,使用的数据为MovieLens数据集。 点击打开链接

代码如下:

<span style="font-size:12px;">def loadMovieLens(path='ml-100k'):
	movies = {}
	for line in open(path+'/u.item'):
		(id,title)=line.split('|')[0:2]
		movies[id]=title
	prefs ={}
	for line in open(path+'/u.data'):
		(user,movieid,rating,ts) = line.split('\t')
		prefs.setdefault(user,{})
		prefs[user][movies[movieid]]=float(rating)
	return prefs

#print loadMovieLens()

prefs = loadMovieLens()
#基于用户的推荐
print getRecommendations(prefs, '87')[0:30]
#基于物品的推荐
itemsim=calculateSimilarItems(prefs, n=50)

print getRecommendItems(prefs, itemsim, '87')</span>
到此为止,完整的推荐算法已经实现完。




你可能感兴趣的:(推荐算法实战)