推荐系统-协同过滤

UserCF流程整理(结合代码)

代码源

1 数据处理

1.1 加载数据

loadfile(filename)函数,功能是利用yield迭代的给后面的generate_dataset()函数逐条的提供数据。主要代码如下:

def loadfile(filename):
    ''' load a file, return a generator. '''
    fp = open(filename, 'r')
    for i, line in enumerate(fp):
        yield line.strip('\r\n')
    fp.close()

enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,同时用yield生成器来逐个返回。这么处理是为了分批的return数据,因为生成器不像list、string用于迭代时将数据一直保存在内存,生成器(Generators)临时产生要迭代的值,且只能用1次,使用后即丢弃,这样可以解决数据量太大,一次全部处理占内存太多甚至内存不足的问题。

另外现在的open()函数都写在with里面,就不用担心漏写.close()函数而占用内存了。

1.2 生成数据集

generate_dataset(self, filename, pivot=0.7)函数,从上面的loadfile()函数逐条获取数据,对该条数据进行切割,分配user、movie、rating值。然后用随机数来分配该条数据放入训练集还是测试集,起到一个shuffle的作用,训练测试比例由参数pivot调节。

trainset与testset用字典唉存储,格式为{“user”:{“movies1”:int(rating1), “movies2”:int(rating2),…, }, …, }

主要代码如下:

def generate_dataset(self, filename, pivot=0.7):
    ''' load rating data and split it to training set and test set '''
    for line in self.loadfile(filename):   # 迭代获取line
        user, movie, rating = line.split('\t')   # rating文件格式UserID::MovieID::Rating::Timestamp
        # split the data by pivot
        if random.random() < pivot:   # 用随机数来随机的将数据添加到训练集或是测试集,起到shuffle的作用
            self.trainset.setdefault(user, {})   # setdefault(key, default=None)即当key不在字典中,就将key添加到字典中,值为设置的默认值。
            self.trainset[user][movie] = int(rating)
        else:
            self.testset.setdefault(user, {})
            self.testset[user][movie] = int(rating)

2 用户的相似度计算

2.1 生成item-user查找表

从trainset中取出数据,建立一个字典结构的item-user查找表movies2users,其中字典的key为电影的ID,value为看过这个电影的userID集合set()。形如:{“movie1ID”:{“user1ID”, “user2ID”,…}, …}

2.2 生成user间共同评分的电影个数矩阵,为计算user相似度做基础

然后根据movies2users里的电影与user的关系,构建用户共同评分矩阵usersim_mat(同样用字典来表示),格式为{user1ID:{useriID:共同评分电影个数, userjID:共同评分电影个数, …}, …},明显这是一个对称矩阵。

2.3 计算用户相似度

该计算在上面的usersim_mat矩阵上进行,没有创建新的矩阵{这里说的矩阵都是用字典表示的},相似度计算方法这里用了余弦相似度:

c o s ( θ ) = a ⋅ b ∣ ∣ a ∣ ∣ × ∣ ∣ b ∣ ∣ cos(\theta)=\cfrac{a \cdot b}{||a||\times||b||} cos(θ)=a×bab

3 CF推荐

协同过滤的推荐有两个超参数K和N分别表示找K个与目标用户相似的其他用户,给他推荐N个商品。

从user_sim_mat矩阵中拿出跟user用户相似度最高的前K个用户,然后遍历他们看过而user没看过的movies,并记录相似度。

最终根据movies的相似排名,取前N个推荐给用户。

def recommend(user):
        ''' Find K similar users and recommend N movies. '''
        K = n_sim_user
        N = n_rec_movie
        rank = dict()
        watched_movies = trainset[user]

        for similar_user, similarity_factor in sorted(user_sim_mat[user].items(), key=itemgetter(1), reverse=True)[0:K]:
            for movie in trainset[similar_user]:
                if movie in watched_movies:
                    continue
                # predict the user's "interest" for each movie
                rank.setdefault(movie, 0)
                # 如果该电影user没看过就追加到rank字典,值为两用户的相似度,后面该电影再出现其值会累加
                rank[movie] += similarity_factor  
        # return the N best movies
        return sorted(rank.items(), key=itemgetter(1), reverse=True)[0:N]

4 效果评估

取出测试集中的用户喜欢的电影,与推荐的电影进行匹配,推荐的电影在用户的训练集列表中即为推荐成功。

评估推荐效果好坏的有四个指标:精确率,召回率,覆盖率,和流行度

符号定义: R ( u ) R(u) R(u)代表根据用户在训练集上的行为给用户做出的推荐列表, T ( u ) T(u) T(u)代表用户在测试集上的行为列表, U U U表示所有的用户, I I I表示所有的物品,覆盖率中分子是给所有用户推荐的物品的集合,分母是所有物品集合。

 Precision  = ∑ u ∈ U ∣ R ( u ) ∩ T ( u ) ∣ ∑ u ∈ U ∣ R ( u ) ∣ \text { Precision }=\frac{\sum_{u \in U}|R(u) \cap T(u)|}{\sum_{u \in U}|R(u)|}  Precision =uUR(u)uUR(u)T(u)

 Recall  = ∑ u ∈ U ∣ R ( u ) ∩ T ( u ) ∣ ∑ u ∈ U ∣ T ( u ) ∣ \text { Recall }=\frac{\sum_{u \in U}|R(u) \cap T(u)|}{\sum_{u \in U}|T(u)|}  Recall =uUT(u)uUR(u)T(u)

 Coverage  = ∣ U u ∈ U R ( u ) ∣ ∣ I ∣ \text { Coverage }=\frac{\mid U_{u \in \mathrm{U}} R(u) \mid}{|I|}  Coverage =IUuUR(u)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值