电影推荐系统 基于内容相似度的召回

电影推荐系统 基于内容相似度的召回

转载代码:https://zhuanlan.zhihu.com/p/98295397
对上述文章代码进行了实际跑通。
废话不说,直接上代码:
数据说明:
item_profile.json user_profile.json 是加工出来的特征。
就是使用所有电影风格作为用户和电影的几个特征列,对每个用户的这几个电影风格列填充,用户评分的所有电影中有这个风格就是1,没有就是0。同样,电影特征列也是使用这几个电影风格,保持和用户的顺序一致。同样做填充1或0,这样就可以做相似度计算了。有些人认为基于这样的特征做相似度计算就是基于内容的推荐了。有些认为基于内容的推荐,大多是文本场景推荐,基于文本内容的向量化做相似度计算。

我认为,这是基于用户的行为产生了用户和物品的属性交换和转移,原来电影的风格属性转移到了用户身上,这样用户和物品有了相同的属性特征维度,就可以进行相似度的度量了。
因此,基于这样的特征做推荐,我感觉叫做基于画像标签的推荐更合适,实际是对用户进行了电影属性的画像,把电影的属性转移到了用户身上。当然画像不仅仅是打标签分类,也可以像这个特征处理一样,将电影的维度维度、及维度层级作为标签对待。

modelSamples.csv 数据是王哲的电影推荐系统,离线处理的数据,这里直接拿来使用,即加工了用户点击的电影的5个风格,作为用户的特征列。

# coding: utf-8 -*-

"""
    Author: Alan
    Desc:
         编写一个基于内容推荐算法的电影推荐系统(训练模型)
"""
import json
import pandas as pd
import numpy as np
import math
import random


class CBRecommend:
    # 加载dataProcessing.py中预处理的数据
    def __init__(self, K):
        # 给用户推荐的item个数
        self.K = K
        self.item_profile = json.load(open("./item_profile.json", "r"))
        self.user_profile = json.load(open("./user_profile.json", "r"))

    # 获取用户未进行评分的item列表
    def get_none_score_item(self, user):
        infile = "E:/IdeaProjects/SparrowRecSys-master/TFRecModel/src/com/sparrowrecsys/sampledata/"
        items = pd.read_csv(infile + "movies.csv")["movieId"].values
        data = pd.read_csv(infile + "ratings.csv")
        have_score_items = data[data["userId"] == user]["movieId"].values
        none_score_items = set(items) - set(have_score_items)
        return none_score_items

    # 获取用户对item的喜好程度(余弦相似度)
    def cosUI(self, user, item):
        user_vec = np.array(self.user_profile.get(str(user), [0]))
        item_vec = np.array(self.item_profile.get(str(item), [0]))

        # print("user_vec = ", user_vec)
        # print("item_vec = ", item_vec)
        Uia = sum(user_vec * item_vec)
        # print("Uia = ", Uia)
        # print(type(Uia))
        if Uia.item() == 0:
            return 0.0
        Ua = math.sqrt(sum([math.pow(one, 2) for one in self.user_profile[str(user)]]))
        Ia = math.sqrt(sum([math.pow(one, 2) for one in self.item_profile[str(item)]]))
        return Uia / (Ua * Ia)

    # 为用户进行电影推荐
    def recommend(self, user):
        user_result = {}
        item_list = self.get_none_score_item(user)
        for item in item_list:
            user_result[item] = self.cosUI(user, item)
        if self.K is None:
            result = sorted(
                user_result.items(), key=lambda k: k[1], reverse=True
            )
        else:
            result = sorted(
                user_result.items(), key=lambda k: k[1], reverse=True
            )[:self.K]
        print(result)

    # 推荐系统效果评估
    def evaluate(self):
        evas = []
        infile = "E:/IdeaProjects/SparrowRecSys-master/TFRecModel/src/com/sparrowrecsys/sampledata/"
        data = pd.read_csv(infile + "ratings.csv")
        # 随机选取20个用户进行效果评估
        for user in random.sample([one for one in range(1, 6040)], 20):
            have_score_items = data[data["userId"] == user]["movieId"].values
            items = pd.read_csv(infile + "movies.csv")["movieId"].values

            user_result = {}
            for item in items:
                user_result[item] = self.cosUI(user, item)
            results = sorted(
                user_result.items(), key=lambda k: k[1], reverse=True
            )[:len(have_score_items)]
            rec_items = []
            for one in results:
                rec_items.append(one[0])
            eva = len(set(rec_items) & set(have_score_items)) / len(have_score_items)
            evas.append(eva)
        return sum(evas) / len(evas)

    # 获取用户、电影属性表示
    def get_users_movies_profile(self):
        infile = "E:/IdeaProjects/SparrowRecSys-master/TFRecModel/src/com/sparrowrecsys/sampledata/modelSamples.csv"
        data = pd.read_csv(infile)
        cols = np.concatenate([data['userGenre1'].unique(),
                               data['userGenre2'].unique(),
                               data['userGenre3'].unique(),
                               data['userGenre4'].unique(),
                               data['userGenre5'].unique()]).astype(np.str)
        genres = np.unique(cols)
        nan = np.array(['nan']).astype(np.str)
        genres = set(np.setdiff1d(genres, nan))
        '''
        {'Action',
         'Adventure',
         'Animation',
         'Children',
         'Comedy',
         'Crime',
         'Documentary',
         'Drama',
         'Fantasy',
         'Film-Noir',
         'Horror',
         'IMAX',
         'Musical',
         'Mystery',
         'Romance',
         'Sci-Fi',
         'Thriller',
         'War',
         'Western'}
        '''

        # 用户属性
        user_profile_tmp = data.groupby('userId').apply(
            lambda df: set(np.setdiff1d(np.unique(np.concatenate([df['userGenre1'].unique(),
                                                                  df['userGenre2'].unique(),
                                                                  df['userGenre3'].unique(),
                                                                  df['userGenre4'].unique(),
                                                                  df['userGenre5'].unique()]).astype(np.str)), nan)))

        user_profile = pd.DataFrame(user_profile_tmp)
        user_profile['userId'] = user_profile.index
        # user_profile.rename(columns={'favor_genres': '0'}, inplace=True)
        user_profile.columns = ['favor_genres', 'userId']
        for genre in genres:
            user_profile[genre] = user_profile['favor_genres'].apply(lambda x: 1 if genre in x else 0)

        # 电影属性
        item_profile_tmp = data.groupby('movieId').apply(
            lambda df: set(np.setdiff1d(np.unique(np.concatenate([df['movieGenre1'].unique(),
                                                                  df['movieGenre2'].unique(),
                                                                  df['movieGenre3'].unique()]).astype(np.str)), nan)))

        item_profile = pd.DataFrame(item_profile_tmp)
        item_profile['movieId'] = item_profile.index
        # user_profile.rename(columns={'favor_genres': '0'}, inplace=True)
        item_profile.columns = ['favor_genres', 'movieId']
        for genre in genres:
            item_profile[genre] = item_profile['favor_genres'].apply(lambda x: 1 if genre in x else 0)

        # 转json形式存储
        # js = item_profile.drop(columns=['favor_genres']).to_json(orient="values", force_ascii=False)
        # filename = "./item_profile.json"
        # with open(filename, 'w', encoding='utf-8') as f:
        #     json.dump(js, f, ensure_ascii=False)
        # items = json.load(open(filename, "r"))
        # items = item_profile.set_index('movieId').drop(columns=['favor_genres']).to_dict('list')
        users = user_profile.drop(columns=['favor_genres']).to_numpy()
        users_dict = {}
        for item in users:
            users_dict[str(item[0])] = item[1:].tolist()
        json.dumps(users_dict)
        filename = "./user_profile.json"
        with open(filename, 'w', encoding='utf-8') as f:
            json.dump(users_dict, f, ensure_ascii=False)

        items = item_profile.drop(columns=['favor_genres']).to_numpy()
        items_dict = {}
        for item in items:
            items_dict[str(item[0])] = item[1:].tolist()
        json.dumps(items_dict)
        filename = "./item_profile.json"
        with open(filename, 'w', encoding='utf-8') as f:
            json.dump(items_dict, f, ensure_ascii=False)


if __name__ == "__main__":
    cb = CBRecommend(K=10)
    simi = cb.cosUI(1, 1)
    cb.recommend(1)
    print(cb.evaluate())



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值