推荐系统实践(四)----基于标签的推荐算法
  标签在我们⽇常⽣活中很常见,打标签作为⼀种重要的⽤户⾏为,蕴含了很多⽤户兴趣信息,因此深⼊研究和利⽤⽤户打标签的⾏为可以很好地指导我们改进个性化推荐系统的推荐质量。举个例⼦,下图是酷我⾳乐的标签,有了标签,⽤户可以快速到⾃⼰感兴趣的歌,同
时酷我也可以通过⽤户经常使⽤的标签,更精确的为⽤户推荐感兴趣的歌曲。1.  原理
  当拿到了⽤户标签⾏为数据,相信⼤家都可以想到⼀个最简单的个性化推荐算法,这⾥我们称为。其描述如下所⽰:
  1. 统计每个⽤户最常⽤标签
  2. 对于每个标签,统计被打过这个标签次数最多的物品
  3. 对于⼀个⽤户,到他常⽤的标签,从⽽到具有这些标签的热门物品进⾏推荐
  ⼀个⽤户标签⾏为的数据集⼀般由⼀个三元组的集合表⽰,其中记录  表⽰⽤户  给物品  打上了标签 。当然,⽤户的真实标签⾏为数据远远⽐三元组表⽰的要复杂,⽐如⽤户打标签的时间、⽤户的属性数据、物品的属性数据等。所以⽤户  对物品  的兴趣公式如下:
  是⽤户  打过标签  的次数,是物品  被打过标签  的次数。
案例分析
  假设我们拥有⼀组⾳乐数据,如下所⽰:
SimpleTagBased
SimpleTagBased (u ,i ,b )u i b u i P (u ,i )=n n b ∑u ,b b ,i
n u ,b u b n b ,i i b
数据处理浅浅爱
利⽤三元组集合表⽰数据集,因为数据是⾃⼰编的,所以本来就是三元组,这⾥只需要简单的处理⼀下就好,使⽤实现,⽤  存储标签数据的三元组,其中 :
def  load_data (file_path ):
records = []
f = open (file_path , "r", encodin
g ="utf-8")
for  line in  f :
info = line .strip ().split ("\t")
records .append (info )纯音乐推荐
return  records
  实现结果为:
[['A', '⼀曲相思', '流⾏'], ['A', '⽣僻字', '流⾏'], ['A', '最后的莫西⼲⼈', '纯⾳乐'], ['A', '倩⼥幽魂', '经典'], ['B', '故乡的原风景', '纯⾳乐'], ['B', '⽣僻字', '流⾏'], ['B', '故乡的原风景', '纯⾳乐'], ['C', '倩⼥幽魂', '经典'], ['C', '海阔天空', '经典'], ['D', '海阔天空', '经典'], ['A', '突然好想你', '寂寞'], ['C', '⾛西⼝', '民歌'], ['D', '
⾛西⼝', '民歌'], ['B', '重头再来', '励志'], ['D', '倩⼥幽魂', '经典'], ['C', '重头再来', '励志'], ['D', '最后的莫西⼲⼈', '纯⾳乐']]
数据处理
统计出  和 ,其中 ,$tag_items = 。
def  InitStat (records ):
雪distanceuser_tags = dict ()  # ⽤户打过标签的次数
tag_items = dict ()  # ⾳乐被打过标签的次数,代表歌曲流⾏度
for  user , item , tag in  records :
user_tags .setdefault (user , dict ())
user_tags [user ].setdefault (tag , 0)
user_tags [user ][tag ] += 1
tag_items .setdefault (tag , dict ())
tag_items [tag ].setdefault (item , 0)
tag_items [tag ][item ] += 1
print ("⽤户打过标签的次数: ", user_tags )
print ("⾳乐打过标签的次数: ", tag_items )
return  user_tags , tag_items
  统计的结果如下所⽰:
⽤户打过标签的次数:  {'A': {'流⾏': 2, '纯⾳乐': 1, '经典': 1, '寂寞': 1}, 'B': {'纯⾳乐': 2, '流⾏': 1, '励志': 1}, 'C': {'经典': 2, '民歌': 1, '励志': 1}, 'D': {'经典': 2, '民歌': 1, '纯⾳乐': 1}}
⾳乐打过标签的次数:  {'流⾏': {'⼀曲相思': 1, '⽣僻字': 2}, '纯⾳乐': {'最后的莫西⼲⼈': 2, '故乡的原风景': 2}, '经典': {'倩⼥幽魂': 3, '海阔天空': 2}, '寂寞': {'突然好想你': 1}, '民歌': {'⾛西⼝': 2}, '励志': {'重头再来': 2}}
Python records records [i ]=[user ,item ,tag ]user _tags tag _items user _tags =n u ,b n b ,i
推荐
有了上⾯获得的数据统计,那么我们就可以根据⽤户对歌曲的兴趣来为⽤户推荐歌曲,兴趣度越⼤,越被优先推荐。
def  Recommend (user , K ):
recommend_items = dict ()
for  tag , wut in  user_tags [user ].items ():
for  item , wti in  tag_items [tag ].items ():
if  item not  in  recommend_items :
recommend_items [item ] = wut * wti    # 计算⽤户对物品兴趣度
else :
recommend_items [item ] += wut * wti
rec = sorted (recommend_items .items (),key = lambda  x :x [1],reverse = True )  # 将推荐歌曲按兴趣度排名
print ("⽤户对歌曲兴趣度: ", rec )
music = []
for  i in  range (K ):
music .append (rec [i ][0])
music = "/".join (music )
print ("为⽤户推荐歌曲: ", music )
每一次当爱在靠近歌词return  music
  可以获得为⽤户推荐的歌单,这⾥需要去除⽤户已经感兴趣的歌,我这⾥还未做处理:
⽤户对歌曲兴趣度: [('⽣僻字', 4), ('倩⼥幽魂', 3), ('⼀曲相思', 2), ('最后的莫西⼲⼈', 2), ('故乡的原风景', 2), ('海阔天空', 2), ('突然好想你', 1)]
推荐歌曲:  ⽣僻字/倩⼥幽魂
2.   推荐完成后,我们再仔细回顾⼀下,发现⼀个问题,如果新出的⼀⾸流⾏歌,举个例⼦,⽐如说《⽣僻字》,这⾸歌可能很多⼈都听过,也都打了标签,那么  就⾮常⼤,那么即使  很⼩,⽤户对《⽣僻字》的兴趣度也会很⼤,就很有可能发⽣推荐错误的情况。  所以上⾯这种推荐算法给热门标签对应的热门物品很⼤的权重,因此会造成推荐热门的物品给⽤户,从⽽降低推荐结果的新颖性。另外,这个公式利⽤⽤户的标签向量对⽤户兴趣建模,其中每个标签都是⽤户使⽤过的标签,⽽标签的权重是⽤户使⽤该标签的次数。这种建模⽅法的缺点是给热门标签过⼤的权重,从⽽不能反应⽤户个性化的兴趣。这⾥我们可以借鉴TF-IDF的思想,对这⼀公式进⾏改进,提出算法:
      记录了标签  被多少个不同的⽤户使⽤过
  总体的实现跟  没有多⼤区别,只是在数据处理这个步骤时,需要统计TagBasedTFIDF
n b ,i n u ,b TagBasedTFIDF P (u ,i )=
n b ∑log(1+n )b (u )n u ,b b ,i n b (u )b SimpleTagBased n b (u )
def InitStat_update(records):
user_tags =dict()# ⽤户打过标签的次数
tag_items =dict()# ⾳乐被打过标签的次数,代表歌曲流⾏度
tag_user =dict()# 标签被⽤户标记次数春泥 庾澄庆
for user, item, tag in records:
user_tags.setdefault(user,dict())
user_tags[user].setdefault(tag,0)
user_tags[user][tag]+=1
tag_items.setdefault(tag,dict())
tag_items[tag].setdefault(item,0)
tag_items[tag][item]+=1
tag_user.setdefault(tag,dict())
tag_user[tag].setdefault(user,0)
tag_user[tag][user]+=1
print("⽤户打过标签的次数: ", user_tags)
print("⾳乐打过标签的次数: ", tag_items)
print("标签被⽤户使⽤次数: ", tag_user)
return user_tags, tag_items, tag_user
  统计结果如下所⽰:
⽤户打过标签的次数:{'A':{'流⾏':2,'纯⾳乐':1,'经典':1,'寂寞':1},'B':{'纯⾳乐':2,'流⾏':1,'励志':1},'C':{'经典':2,'民歌':1,'励志':1},'D':{'经典':2,'民歌': 1,'纯⾳乐':1}}
⾳乐打过标签的次数:{'流⾏':{'⼀曲相思':1,'⽣僻字':2},'纯⾳乐':{'最后的莫西⼲⼈':2,'故乡的原风景':2},'经典':{'倩⼥幽魂':3,'海阔天空':2},'寂寞':{'突然好想你':1},'民歌':{'⾛西⼝':2},'励志':{'重头再来':2}}
标签被⽤户使⽤次数:{'流⾏':{'A':2,'B':1},'纯⾳乐':{'A':1,'B':2,'D':1},'经典':{'A':1,'C':2,'D':2},'寂寞':{'A':1},'民歌':{'C':1,'D':1},'励志':{'B':1,'C':1} }
TagBasedTFIDF
  同时推荐的算法,修正为 :
def Recommend_update(user, K):韩国站
recommend_items =dict()
for tag, wut in user_tags[user].items():
for item, wti in tag_items[tag].items():
if item not in recommend_items:
recommend_items[item]= wut * wti/log(1+len(tag_user[tag]))# 计算⽤户对物品兴趣度
else:
recommend_items[item]+= wut * wti/log(1+len(tag_user[tag]))
rec =sorted(recommend_items.items(),key =lambda x:x[1],reverse =True)# 将推荐歌曲按兴趣度排名
print("⽤户对歌曲兴趣度", rec)
music =[]
for i in range(K):
music.append(rec[i][0])
music ="/".join(music)
print("为⽤户推荐歌曲: ", music)
return music
  最终推荐结果为,这⾥需要去除⽤户已经感兴趣的歌,我这⾥还未做处理::
⽤户对歌曲兴趣度:[('⽣僻字',3.6409569065073493),('倩⼥幽魂',2.1640425613334453),('⼀曲相思',1.8204784532536746),('最后的莫西⼲⼈',1.442695 0408889634),('故乡的原风景',1.4426950408889634),('海阔天空',1.4426950408889634),('突然好想你',1.4426950408889634)]
推荐歌曲:⽣僻字/倩⼥幽魂
  因为我们这⾥数据量⽐较少,所以看不出来效果,如果各位看官感兴趣,可以⾃⼰去⽹上获取数据,来实践⼀下效果。 
3.    同理,我们也可以借鉴  的思想对热门物品进⾏惩罚,从⽽得到  算法:
      记录了物品i被多少个不同的⽤户打过标签
  因为代码实现⽅式和  区别不⼤,这⾥我就不实现了,有兴趣的童鞋可以⾃⼰动⼿试试。
4. 分析TagBasedTFIDF ++
TF −IDF TagBasedTFIDF ++P (u ,i )=b ∑log(1+n )b (u )n u ,b log(1+n )
i (u )n b ,i n i (u )TagBasedTFIDF