智能推荐

推荐算法之物品协同过滤

2019-04-07  本文已影响24人  Byte猫

一、概念

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

用户协同过滤的缺陷
(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()
上一篇下一篇

猜你喜欢

热点阅读