美文网首页智能推荐
推荐算法之物品协同过滤

推荐算法之物品协同过滤

作者: Byte猫 | 来源:发表于2019-04-07 14:25 被阅读24次

    一、概念

    用户协同过滤并不总是合适的。

    用户协同过滤的缺陷
    (1)拓展性:用户协同过滤的计算量会随着用户数目的增长而增长。在几千用户时效果还好,但是有上百万用户时拓展性就成了一个问题。
    (2)稀疏性:大部分推荐系统中,用户和商品都很多,但是用户评级的平均商品数目较少。所以使用用户协同过滤有可能找不到最近邻居。

    为了解决用户协同过滤的缺陷,于是又有了物品协同过滤(ItemCF)。ItemCF 的原理是,为用户推荐那些和他之前喜欢的物品相似的物品。例如,算法可能会因为用户买过《推荐系统实践》而为用户推荐《推荐系统》。
    可以抽象为user->item->item, 推荐与其喜欢的item相似的item,简称item-based

    对比user-based和item-based
    user-based更多的考虑相同爱好的用户兴趣,推荐这些用户喜欢/访问过的item,和用户当前的行为关系不大,更多的是用户的这些朋友访问过什么,属于圈子的社会化行为,推荐的item是相同爱好用户最喜欢的item,所以具备热点效应,也就是推荐圈子用户访问最多的;同时也可以将圈子用户刚刚访问item推荐出来,具备很强的实时性,尤其是新引入的热点,可以很快的扩散,也能解决new-item的冷启动问题。
    item-based 主要考虑用户历史兴趣,推荐与用户历史喜欢item相似的item,和用户的当前行为有很大的关系,推荐的item与用户当前click的相似性,用户是可以理解的,也就是所谓的可解释性很强,推荐的item也不是热门的,很有可能是冷门(长尾),但是和用户的兴趣相关,要求用户在这个网站上的兴趣是长久和固定的,推荐的意义在于帮助用户找到和其兴趣相关的item。

    二、实现物品协同过滤

    1、执行步骤

    step 1:建立物品-物品共现矩阵
    step 2:计算物品间相似度
    step 3:针对目标用户u,对其浏览过的物品找到其最相似的K个物品,产生N个推荐

    2、代码实现

    采用GroupLens提供的MovieLens数据集 ,包含6000多用户对4000多部电影的100万条评分。该数据集是一个评分数据集,用户可以给电影评1-5分5个不同的等级。
    本文着重研究隐反馈数据集中TopN推荐问题,因此忽略了数据集中的评分记录。也就是说,TopN推荐的任务是预测用户会不会对某电影评分,而不是预测用户在准备对某部电影评分的前提下会给电影评多少分。

    # coding=utf-8
    '''
    物品协同过滤推荐
    '''
    import random
    import math
    from operator import itemgetter
        
    #========================================================
    #  核心算法
    #========================================================
    
    class itemBasedCF():
    
        def __init__(self):
            '''
            初始化相关参数
            '''
            # 每个物品查找相似个数
            self.n_sim_item = 10
            # 推荐数量
            self.n_rec_item = 10
     
            # 训练用的数据集
            self.dataSet = {}
     
            # 物品相似度矩阵
            self.item_sim_matrix = {}  # 使用典中典模拟矩阵
    
            print('配置:推荐数 = %d' % self.n_rec_item)
    
        def load_file(self, filename):
            '''
            读文件,返回文件的每一行
            INPUT  -> 文件名
            '''
            with open(filename, 'r') as f:
                for i, line in enumerate(f):
                    if i == 0:  # 去掉文件第一行的title
                        continue
                    yield line.strip('\r\n')
            print('Load %s success!' % filename)
    
        def get_dataset(self, filename):
            '''
            读文件得到评分数据
            INPUT  -> 文件名
            '''
            dataSet_len = 0
            for line in self.load_file(filename):
                user, item, rating, timestamp = line.split('::')
                self.dataSet.setdefault(user, {})
                # 键中键:形如{'1': {'1287': '2.0', '1953': '4.0', '2105': '4.0'}, '2': {'10': '4.0', '62': '3.0'}}
                # 用户1看了id为1287的电影,打分2.0
                self.dataSet[user][item] = rating
                dataSet_len += 1
            print('样本量 = %s' % dataSet_len)
        
        def itemSimilarity(self):
            '''
            计算物品间相似度
            '''
            print("STEP1:构建item-item共现矩阵...")
            # item-item共现矩阵C_matrix
            C_matrix = dict()
            # 物品被多少个不同用户购买
            item_hot = dict()
            for user, items in self.dataSet.items():
                for i in items.keys():
                    item_hot.setdefault(i, 0)
                    item_hot[i] += 1
                    C_matrix.setdefault(i, {})
                    for j in items.keys():
                        if i == j:
                            continue
                        C_matrix[i].setdefault(j, 0)
                        weight = 1
                        # 根据热门程度加权
                        # weight = 1 / math.log2(1+len(items))
                        C_matrix[i][j] += weight
            print("item-item共现矩阵构建完成! ")
     
            print('STEP2:计算物品间相似度 ...')
            for i, related_items in C_matrix.items():
                for j, count in related_items.items(): # count表示物品与物品共现次数
                    # 计算物品间相似度
                    self.item_sim_matrix[i][j] = count / math.sqrt(item_hot[i] * item_hot[j])
            print('物品间相似度计算完成!')
     
        def recommend(self, user):
            '''
            针对目标用户,产生N个推荐
            INPUT  -> 待推荐用户
            '''
            K = self.n_sim_item
            N = self.n_rec_item
            rank = {}
            watched_items = self.dataSet[user]
     
            for i, interest in watched_items.items():
                for j, sim in sorted(self.item_sim_matrix[i].items, key=itemgetter(1), reverse=True)[0:K]:
                    if j in watched_items:
                        continue
                    rank.setdefault(j, 0)
                    rank[j] += float(interest) * float(sim)
            return sorted(rank.items(), key=itemgetter(1), reverse=True)[0:N]   # 返回最可能感兴趣的N个
     
    #========================================================
    #  主程序
    #========================================================
    
    if __name__ == '__main__':
    
        rating_file = 'ratings3.csv'
        # 初始化
        itemCF = itemBasedCF()
        # 读取评分文件
        itemCF.get_dataset(rating_file)
        # 构建物品相似度矩阵
        itemCF.itemSimilarity()
    

    相关文章

      网友评论

        本文标题:推荐算法之物品协同过滤

        本文链接:https://www.haomeiwen.com/subject/miqjiqtx.html