协同过滤算法学习笔记与相似度矩阵Python实现

显示/隐式反馈

类似视频的评分、商品的评分这些为显示反馈;浏览日志、购买日志这些为隐式反馈。

用户行为的统一表示方法

userId、itemId、behaviorType、context(上下文,时间地点等)、behaviorWeight、behaviorContent

常见数据集种类

  1. 无上下文的隐式反馈数据集:仅记录用户和物品的ID
  2. 无上下文的显示反馈数据集:记录物品和用户的ID以及评分
  3. 有上下文的隐示反馈数据集:记录用户和物品的ID以及物品产生行为的时间戳
  4. 有上下文的显示反馈数据集:记录用户和物品的ID以及评分和时间戳

评价指标

  1. 召回率:正确推荐的数目/总共喜欢的数目
  2. 准确率:正确推荐的数目/推荐出来的数目
  3. 覆盖率:推荐的种类/总类数
  4. 流行度:顾名思义
  5. AUC:正确的样本排在错误样本前面的概率

基于用户的协同过滤算法(UserCF)

  1. 给用户推荐和他兴趣相似的其他用户喜欢的物品,比较社会化。适用于时效性较强的领域,如新闻推荐。
  2. 步骤:(1)找到和目标用户兴趣类似的用户集合。(2)找到这个集合中用户喜欢的,且目标用户还没有听说过的物品推荐给目标用户。
  3. 用户相似度计算:(1)Jaccard公式/余弦相似度,适用于用户较少的情况。(2)物品-用户倒排表,一个二维矩阵,行列都是用户ID,以物品为纽带,如果两个用户之间有关联则在矩阵中加一。C[u][v] += 1, W[u][v] = Cuv / math.sqrt(N[u] * N[v])
  4. 对推荐结果有较大影响的因素:推荐的数目。
  5. 算法的改进:(1)User-IIF,减少流行物品对相似度的影响。C[u][v] += 1 / math.log(1 + len(user)), W[u][v] = Cuv / math.sqrt(N[u] * N[v])

基于物品的协同过滤算法(ItemCF)

  1. 给用户推荐和他之前喜欢物品类似的物品,比较个性化。适用于个性化需求较强烈的领域,如一些购物平台。
  2. 步骤:(1)计算物品之间的相似度。(2)根据物品的相似度和用户的历史行为给用户生成推荐列表。
  3. 物品相似度计算:用户-物品倒排表(对每个用户建立一个包含他喜欢的物品列表),然后对于每个用户将它物品列表中的物品两两在共现矩阵C加一。
    C[i][j] += 1, W[i][j] = Cij / math.sqrt( N[i] * N[j])
  4. 算法优化:(1)User-IUF,活跃用户对物品相似度的贡献应该小于不活跃用户。
    C[i][j] += 1 / math.log(1 + len(item) * 1.0 ), W[i][j] = Cij / math.sqrt( N[i] * N[j])。
    (2)User-Norm,归一化相似度矩阵。

UserCF与ItemCF的优缺点对比

UserCF ItemCF
性能 适用于用户较少的场合 适用于物品数目明显小于用户数的场合
领域 时效性较强,个性化兴趣不太明显 长尾物品丰富
实时性 用户有新行为不一定导致推荐结果立即变化 用户有新行为一定会导致推荐结果实时变化
冷启动 在新用户对很少物品产生行为后不能立即进行个性化推荐,因为用户相似度是每隔一段时间离线计算的;新物品上线一段时间后,一旦有用户对物品产生行为就可以将它推给其他人 新用户只要对一个物品产生行为就可以给他推荐相关物品;没有办法在不离线更新物品相似度表的情况下将新物品退给用户
推荐理由 难以提供 可以解释

核心代码(基于ml-100k数据集)

计算相似度矩阵
        def ItemCF_Norm(self):
        # 建立物品-物品的共现矩阵
        C = dict()  # 物品-物品的共现矩阵
        N = dict()  # 物品被多少个不同用户购买
        for user, items in self.train.items():
            for i in items.keys():
                N.setdefault(i, 0)
                N[i] += 1
                C.setdefault(i, {
     })
                for j in items.keys():
                    if i == j: continue
                    C[i].setdefault(j, 0)
                    C[i][j] += 1
                    #C[i][j] += 1 / math.log(1 + len(items) * 1.0)  # IUF
        # 计算相似度矩阵
        self.W = dict()
        for i, related_items in C.items():
            self.W.setdefault(i, {
     })
            for j, cij in related_items.items():
                self.W[i][j] = cij / (math.sqrt(N[i] * N[j]))
        # 归一化
        for item1, dic in self.W.items():
            max = sorted(self.W[item1].items(), key=lambda x: x[1], reverse=True)[0][1]
            for item2, sim in dic.items():
                self.W[item1][item2] = self.W[item1][item2] / max
        self.SaveDict('data/itemcf_norm.data', self.W)
        return self.W
带理由的推荐
    def Recommend(self, user, K=10, num_recommend=10, num_recent=5):
        rank = dict()
        watched_item = self.train[user]  # 用户user产生过行为的item和评分
        recent_item = self.getRecent(user, num_recent)  # 看过的并且喜欢(4分以上)的电影按时间排序
        for movie, list in recent_item:
            for related_movie, w in sorted(self.W[movie].items(), key=lambda x: x[1], reverse=True)[:K]:
                if related_movie in watched_item.keys():
                    continue
                rank.setdefault(related_movie, [0, movie])
                rank[related_movie][0] += list[0] * w  # list[0]是评分 list[1]是时间
        return dict(sorted(rank.items(), key=lambda x: x[1], reverse=True)[0:num_recommend])
召回率与准确率的计算
 def Recall(self, N=30):
        hit = 0
        all = 0
        for user_id in self.train.keys():
            if user_id in self.test.keys():
                tu = self.test[user_id]
                rank = self.Recommend(user_id, num_recommend=N)
                for item_id, pui in rank.items():
                    if item_id in tu.keys():
                        hit += 1
                all += len(tu)
        return hit / (all * 1.0)

    def Precision(self, N=30):
        hit = 0
        all = 0
        for user_id in self.train.keys():
            if user_id in self.test.keys():
                tu = self.test[user_id]
                rank = self.Recommend(user_id, num_recommend=N)
                for item_id, pui in rank.items():
                    if item_id in tu.keys():
                        hit += 1
                all += N
        return hit / (all * 1.0)

你可能感兴趣的:(推荐系统,ml-100k,python,ItemCF,协同过滤)