chapter3:协同过滤-隐式评级及基于物品的过滤

   前面提到,有一些证据表明,用户通常不使用细粒度的区分机制,而是倾向于要不给最高评分要不给最低评分。这种非此即彼的极端评级方式有时可能会导致结果无法使用。本章将考察对协同过滤的调优方法,以便更高效低产生更精确的推荐结果。

   显示评级:指用户显示地给出物品的评级结果。如点赞/点差/评分

   隐式评级:观察用户的行为来获得结果。如跟踪用户在纽约时报在线上的点击轨迹,对某个用户的点击行为观察几周之后,就能够构建该用户的合理画像(profile),比如,他不喜欢体育新闻但是好像喜欢技术新闻。如果他点击了iPhone的广告,那么或许他对该产品感兴趣。另一种隐式评级来自用户实际的购买结果。

一、显示评级的问题

   问题1:用户大都具有惰性,不愿对物品评级

   问题2:用户可能撒谎或者只给出部分信息

   问题3:用户不会更新其评级结果

   隐式评级有哪些问题呢?

      可能并不是给自己买,导致用户画像很奇怪

二、隐式数据

网页: 点击指向某个网页的链接

    浏览页面的时间

    重复的访问

    将一个网页指向其他网页

    在Hulu上观看的视频

音乐播放器: 用户播放的歌曲

       用户跳过的歌曲

       某首歌曲播放的次数

无论是显示数据还是隐式数据,第二章介绍的算法都可以适用

三、成功带来的问题

  假设你有100万用户,进行一次推荐时需要计算100万次距离计算

  所以,基于邻居的推荐系统的最主要缺点是延迟性太差。幸运的是,该问题有办法解决

  1、基于用户的过滤(也称为基于内存的协同过滤)

    有两个问题:扩展性和稀疏性

  2、基于物品的过滤(基于模型的协同过滤)

    可以计算出最相似的两件物品

四、调整后的余弦相似度

  论文Item-based collaborative filtering recommendation algorithms


(Ru,i - Ru) 指的是用户u给物品i的评分减去用户u对所有物品的评分的平均值。S(i, j)指物品i和物品j之间的相似度、

def computeSimilarity(band1, band2, userRatings):
   averages = {}
   for (key, ratings) in userRatings.items():
      averages[key] = (float(sum(ratings.values()))
                      / len(ratings.values()))

   num = 0  # numerator
   dem1 = 0 # first half of denominator
   dem2 = 0
   for (user, ratings) in userRatings.items():
      if band1 in ratings and band2 in ratings:
         avg = averages[user]
         num += (ratings[band1] - avg) * (ratings[band2] - avg)
         dem1 += (ratings[band1] - avg)**2
         dem2 += (ratings[band2] - avg)**2
   return num / (sqrt(dem1) * sqrt(dem2))

我们已经得到了相似度矩阵,如果能够利用该矩阵进行预测那就太好了(比如,我想知道David有多喜欢Kacey Musgraves?)

p(u, i) 指用户对物品i的喜欢程度


五、Slope One算法

另一种流行的基于物品过滤的算法是Slop One,主要优点是简洁性,因此它很容易实现

论文Slope One Predictors for online Rating-Based Collaborative Filtering 值得阅读


可以将Slope One看成两部分

  第一部分,事先计算的部分(批处理模式,可以是半夜或任何时间进行),称为每对物品之间的偏差(deviation),可以得到物品偏差构成的数据库


  第二部分,利用偏差实际预测,利用加权Slope One算法进行预测


基于Python的实现

   def computeDeviations(self):
      # for each person in the data:
      #    get their ratings
      for ratings in self.data.values():
         # for each item & rating in that set of ratings:
         for (item, rating) in ratings.items():
            self.frequencies.setdefault(item, {})
            self.deviations.setdefault(item, {})                    
            # for each item2 & rating2 in that set of ratings:
            for (item2, rating2) in ratings.items():
               if item != item2:
                  # add the difference between the ratings to our
                  # computation
                  self.frequencies[item].setdefault(item2, 0)
                  self.deviations[item].setdefault(item2, 0.0)
                  self.frequencies[item][item2] += 1
                  self.deviations[item][item2] += rating - rating2
        
      for (item, ratings) in self.deviations.items():
         for item2 in ratings:
            ratings[item2] /= self.frequencies[item][item2]
   def slopeOneRecommendations(self, userRatings):
      recommendations = {}
      frequencies = {}
      # for every item and rating in the user's recommendations
      for (userItem, userRating) in userRatings.items():
         # for every item in our dataset that the user didn't rate
         for (diffItem, diffRatings) in self.deviations.items():
            if diffItem not in userRatings and \
               userItem in self.deviations[diffItem]:
               freq = self.frequencies[diffItem][userItem]
               recommendations.setdefault(diffItem, 0.0)
               frequencies.setdefault(diffItem, 0)
               # add to the running sum representing the numerator
               # of the formula
               recommendations[diffItem] += (diffRatings[userItem] +
                                             userRating) * freq
               # keep a running sum of the frequency of diffitem
               frequencies[diffItem] += freq
      recommendations =  [(self.convertProductID2name(k),
                           v / frequencies[k])
                          for (k, v) in recommendations.items()]
      # finally sort and return
      recommendations.sort(key=lambda artistTuple: artistTuple[1],
                           reverse = True)
      # I am only going to return the first 50 recommendations
      return recommendations[:50]

六、MovieLens数据集

明尼苏达大学GroupLens研究项目所收集的MovieLens数据集包含用户对影片的评分 www.grouplens.org

这里使用了其中最小规模的数据集ml-100k

>>> import recommender3
>>> r = recommender3.recommender(0)
>>> r.loadMovieLens('ml-100k/')
102625
>>> r.showUserTopItems('1', 50)
When Harry Met Sally... (1989)	5
Jean de Florette (1986)	5
Godfather, The (1972)	5
...
>>> r.computeDeviations()   #在我的笔记本上大概需要30秒
>>> r.slopeOneRecommendations(r.data['1'])
>>> r.slopeOneRecommendations(r.data['25'])
最后:
1、你可以对MovieLens数据集中的10部影片进行评级,看看Slope One推荐系统会给你推荐什么影片?你是否喜欢

2、实现调整的余弦相似度计算方法,将其性能与Slope One进行比较

3、运行Booking Crossing数据集,dataset有27万本书被评分,因此需要一个270000x270000的字典存储偏差值,这大概需要730亿个字典条目。对于MovieLens数据集,其字典的稀疏度如何?修改代码以便能够处理更大的数据集



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值