利用用户标签数据

Poblog 08月09日 2018


推荐系统的目的:联系用户的兴趣和物品

流行的推荐系统基本上通过3种方式联系用户兴趣和物品

1.利用用户喜欢过的物品,给用户推荐与他喜欢过的物品相似的物品,这就是前面提到的基于物品的算法

2.利用和用户兴趣相似的其他用户,给用户推荐那些和他们兴趣爱好相似的其他用户喜欢的物品,这是前面提到的基于用户的算法

3.通过一些特征(feature)联系用户和物品,给用户推荐那些具有用户喜欢的特征的物品

特征有不同的表现方式,比如可以表现为物品的属性集合(比如对于图书,属性集合包括作者、出版社、主题和关键词等) ,也可以表现为隐语义向量

讨论一种重要的特征表现方式——标签

标签是一种无层次化结构的、用来描述信息的关键词,它可以用来描述物品的语义

标签应用一般分为两种:
让作者或者专家给物品打标签
让普通用户给物品打标签,也就是UGC

用户对一个物品打上一个标签,这个标签一方面描述了用户的兴趣,另一方面则表示了物品的语义,从而将用户和物品联系了起来

主要讨论UGC的标签应用,研究用户给物品打标签的行为,探讨如何通过分析这种行为给用户进行个性化推荐

UGC 标签系统的代表应用

鼻祖Delicious
论文书签网站CiteULike
音乐网站Last.fm
视频网站Hulu
书和电影评论网站豆瓣

标签系统中的推荐问题

标签系统中的推荐问题主要有以下两个

如何利用用户打标签的行为为其推荐物品(基于标签的推荐)
如何在用户给物品打标签时为其推荐适合该物品的标签(标签推荐)

需要解答下面3个问题
 用户为什么要打标签
 用户怎么打标签
 用户打什么样的标签

 用户的标注行为:
 有些用户标注是给内容上传者使用的(便于上传者组织自己的信息)
 有些用户标注是给广大用户使用的(便于帮助其他用户找到信息)

 用户如何打标签:
 尽管每个用户的行为看起来是随机的,但其实这些表面随机的行为背后蕴含着很多规律

 打什么样的标签
 用户往往不是按照我们的想法操作,而是可能会给物品打上各种各样奇奇怪怪的标签

 总结了 Delicious 上的标签,将它们分为如下几类:
 表明物品是什么
 表明物品的种类
 表明谁拥有物品
 表达用户的观点
 用户相关的标签
 用户的任务


 Hulu 对视频的标签就做了分类:
 类型
 时间
 人物
 地点
 语言
 奖项
 其他

 基于标签的推荐系统
 豆瓣
 在每本书的页面上,豆瓣都提供了一个叫做“豆瓣成员常用标签”的应用,它给出了这本书上用户最常打的标签。同时,在用户给书做评价时,豆瓣也会让用户给图书打标签

 最终的个性化推荐结果里,豆瓣利用标签将用户的推荐结果做了聚类,显示了对不同标签下用户的推荐结果,从而增加了推荐的多样性和可解释性

 一个用户标签行为的数据集一般由一个三元组的集合表示,其中记录 (u, i, b)  表示用户 u 给物品 i 打上了标签 b 


用物品标签向量的余弦相似度度量物品之间的相似度

其中 item_tags[i][b] 是对物品 i 打标签 b 的次数,那么物品 i 和 j 的余弦相似度可以通过如下程序计算

#计算余弦相似度

def CosineSim(item_tags,i,j):
  
//item_tags:物品出现tag的次数
    {'196': {'tag1':9,'tag2':19,...},...}
    i:'196'
    j:'197'
  //

    ret = 0
    for b,wib in item_tags[i].items():     #求物品i,j的标签交集数目
        
//b:'tag1' 标签
  wib:9   被打标签的次数
//

        if b in item_tags[j]:
    
//标签出现在物品j的列表中
    //

            ret += wib * item_tags[j][b]
    
//ret:记录共有标签的乘积
    //

    ni = 0
    nj = 0
    for b, w in item_tags[i].items():      #统计 i 的标签数目
      
//b:'tag1' 标签
w:9   被打标签的次数
      //

        ni += w * w
//ni:记录物品i标签的平方和
//

    for b, w in item_tags[j].items():      #统计 j 的标签数目
       
//b:'tag1' 标签
  w:9   被打标签的次数
         //

        nj += w * w
//nj:记录物品j标签的平方和
//

    if ret == 0:
        return 0
    return ret/math.sqrt(ni * nj)          #返回余弦值
    
//余弦相似度
    //




 #计算推荐列表多样性  
 
def Diversity(item_tags,recommend_items):
   
//item_tags:物品出现tag的次数
     {'196': {'tag1':9,'tag2':19,...},...}
     recommend_items:{'196','197',...} 推荐物品列表
   //

    ret = 0  
    n = 0  
    for i in recommend_items.keys():
      
//i:'196'
      //

        for j in recommend_items.keys():
           
//j:'197'
   //

            if i == j:  
                continue  
            ret += CosineSim(item_tags,i,j)
    
//ret:记录推荐物品余弦相似度和
    //

            n += 1  
    
//n记录全部物品个数
    //

    return ret/(n * 1.0) 
    
//返回平均余弦相似度
    //


推荐系统的多样性为所有用户推荐列表多样性的平均值



一个最简单的算法

  统计每个用户最常用的标签
  对于每个标签,统计被打过这个标签次数最多的物品
  对于一个用户,首先找到他常用的标签,然后找到具有这些标签的最热门物品推荐给这
  个用户


#推荐算法  
def Recommend(usr):  
    recommend_list = dict();  
    tagged_item = user_items[usr];#得到该用户所有推荐过的物品  
    
//tagged_item:该用户的标签记录
    {'tag1':9,'tag2':19,...}
    //

    for tag_,wut in user_tags[usr].items():#用户打过的标签及次数 
        
//tag_:'tag1' 用户打过的标签
  wut:9  用户打过该标签次数 
//

        for item_,wit in tag_items[tag_].items():
  
// tag_items[tag_].items() 存放打过该标签的物品及标签次数
     item_:'196' 被打过该标签的物品
     wit:9  被打过该标签的物品被打过该标签的次数
   //

            if item_ not in tagged_item:#已经推荐过的不再推荐  
                if item_ not in recommend_list:  
                    recommend_list[item_]=wut*wit;#根据公式  
                else:  
                    recommend_list[item_]+=wut*wit;  
  
//计算推荐权重
  //

    return sorted(recommend_list.iteritems(), key=lambda a:a[1],reverse=True)
    //返回推荐列表按推荐权重的排序



 算法的改进:

 TF-IDF
 前面这个公式倾向于给热门标签对应的热门物品很大的权重, 因此会造成推荐热门的物品给用户,从而降低推荐结果的新颖性.
 解决:推荐权重/log(1+标签 b 被多少个不同的用户使用过),这个算法记为 TagBasedTFIDF
 实验结果相对比,可以看到该算法在所有指标上相比 SimpleTagBased 算法都有提高

 同理,我们也可以借鉴 TF-IDF 的思想对热门物品进行惩罚,从而得到如下公式
 解决:推荐权重/log(1+标签 b 被多少个不同的用户使用过)/log(1+物品 i 被多少个不同的用户打过标签)
 这个算法记为 TagBasedTFIDF++ 
 和 TagBasedTFIDF 算法相比,除了多样性有所下降,其他指标都有明显提高。
 结果表明,适当惩罚热门标签和热门物品,在增进推荐结果个性化的同时并不会降低推荐结果的离线精度
 

 数据稀疏性

 对于新用户或者新物品,为了提高推荐的准确率,我们可能要对标签集合做扩展,比如若用户曾经用过“推荐系统”这个标签,我们可以将这个标签的相似标签也加入到用户标签集合中,比如“个性化” 、 “协同过滤”等标签

 标签扩展有很多方法,其中常用的有话题模型(topic model) ,不过这里遵循简单的原则介绍一种基于邻域的方法.

 标签扩展的本质是对每个标签找到和它相似的标签,也就是计算标签之间的相似度

 最简单的相似度可以是同义词。如果有一个同义词词典,就可以根据这个词典进行标签扩展。如果没有这个词典,我们可以从数据中统计出标签的相似度.

 如果认为同一个物品上的不同标签具有某种相似度, 那么当两个标签同时出现在很多物品的标签集合中时,我们就可以认为这两个标签具有较大的相似度.

 进行标签扩展确实能够提高基于标签的物品推荐的准确率和召回率,但可能会稍微降低推荐结果的覆盖率和新颖度

 标签清理
 不是所有标签都能反应用户的兴趣。比如,在一个视频网站中,用户可能对一个视频打了一个表示情绪的标签,比如“不好笑” ,但我们不能因此认为用户对“不好笑”有兴趣,并且给用户推荐其他具有“不好笑”这个标签的视频.标签系统里经常出现词形不同、词义相同的标签.

 标签清理的另一个重要意义在于将标签作为推荐解释。如果我们要把标签呈现给用户,将其作为给用户推荐某一个物品的解释,对标签的质量要求就很高.标签不能包含没有意的停止词或者表示情绪的词,其次这些推荐解释里不能包含很多意义相同的词语

 一般来说有如下标签清理方法:
  去除词频很高的停止词
  去除因词根不同造成的同义词,比如 recommender system 和 recommendation system
  去除因分隔符造成的同义词,比如 collaborative_filtering 和 collaborative-filtering 

  为了控制标签的质量,很多网站也采用了让用户进行反馈的思想,即让用户告诉系统某个标签是否合适