基于内容推荐算法的电影推荐系统

您所在的位置:网站首页 算法rating 基于内容推荐算法的电影推荐系统

基于内容推荐算法的电影推荐系统

2023-09-20 06:29| 来源: 网络整理| 查看: 265

基于内容的推荐算法

格局用户过去一段时间内喜欢的物品,以及由此推算出来用户偏好,为用户推荐相似物品。其中的“内容”指的便是:用户过去一段时间内喜欢的物品,以及由此推算出来的用户偏好。

算法原理: 基于内容(Content based ,CB)的推荐原理:

向用户推荐所喜欢的Item的相似的Item。 (1)构造Item的特征: (2) 计算Item内容之间的相似度; (3)评判用户是否喜欢某个Item。

1.构造Item的特征

在真实应用场景中,往往会用一些属性描述Item的特征,这些属性通常分为以下两种: .结构化属性:意义明确,其取值固定在某个范围内。 .非结构化属性:特征意义相对不太明确,取值没有什么限制,不可以直接使用。

例子:在电商网站中,Item就是一个商品。例如,Item如果是鞋子,那么尺寸、颜色、品牌等都是结构化属性。 非结构化的数据,需要利用技术手段或人工进行拆分和标注,使之成为结构化数据,才能是使用。

2.计算Item之间的相似度

在确定好Item的特征和用户的偏好模型后,需要计算两个Item之间的相似度。 优化:****使用训练数据得到用户的偏好信息矩阵和物品的特征信息矩阵,然后计算用户对于未进行评分的电影的偏好分,选取前K个推荐给用户。

3.评判用户是否喜欢

在推荐算法中评判用户是否喜欢某个Item就是:利用监督学习或非监督学习的方法,来评判用户喜欢哪些Item,不喜欢那些ITtem,从而为他生成一个偏好模型,对未知的Item进行喜好评判。

结构化数据: 离散型数据:只能采用自然数或整数单位计算的变量。例如,商品属性的唯一编码,虽然是一个整数,但是数值没有意义,只是一个唯一标识。 连续型数据:在一定区间内可以任意取值的变量。例如,商品属性中的长度152.3cm,宽度52.5cm。

注意:使用离散数据和连续型数据需要进行数据归一化处理,实现0-1标准化

基于内容推荐实例 1.实现思路

计算每两个Item内容之间的相似度所产生的算法复杂度是很高的,所以进行优化:首先使用训练数据得到用户的偏好信息矩阵和物品的特征信息矩阵,然后计算用户对于未进行评分的电影的偏好分,选取前K个推荐给用户。

2.构建电影的特征信息矩阵

例如: A电影的类型为:Animation|Children’s|Comedy b电影的类型为:Adventure|Children’s|Fantasy 这里假设电影类型为:[Adventure,Animation,Comedy,Children’s,Fantasy]中的一种或几种。对于算法模型来说,这里的类型的名字是没有办法直接使用的,需要将其转化为数字才能够使用。将每条数据的电影类型用一维矩阵表示,则A为[0,1,1,1,0],B为[1,0,0,1,1]。

3.构建用户偏好信息

图表是一个用户-电影评分表(满分5分,空表示未评分) 在这里插入图片描述 可以看出张三更喜欢《山楂树之恋》和《芳华》这两部电影。 假设这两部电影都属于青春类型,那么推断出张三喜欢青春类型电影,这样就可以为张三构建偏好信息: (1)张三的电影平均分:sum=(4+5)/3=4. (2)根据下面的公式计算出张三对青春电影的偏好程度。 在这里插入图片描述 (3)为用户建立偏见矩阵:其中每个元素表示用户对每种电影类型的偏好程度,如张三偏好矩阵为[0.5,…]

4.计算用户与每部电影的距离

用户与每部电影的余弦相似度越高,则说明用户对电影的偏好程度越高。 在这里插入图片描述

5.代码实现

1.准备数据(数据格式转换) 为了数据方便这里将data 下面 ml-1m的数据 users.dat movies.dat ratings.dat 转化为CSV文件。 以users.dat为例 开始转换用户数据

def process_user_data(self, file='./data/ml-1m/users.dat'): if os.path.exists("data/users.csv"): print("user.csv已经存在") fp = pd.read_table(file, sep='::', engine='python',names=['UserID', 'Gender', 'Age', 'Occupation', 'Zip-code']) fp.to_csv('data/users.csv', index=False)

2.获取item的特征信息矩阵

# 获取item的特征信息矩阵 def prepare_item_profile(self,file='data/movies.csv'): items=pd.read_csv(file) item_ids=set(items["MovieID"].values) #MovieID{1,2,3,4,.....} self.item_dict={}#{1: ['Animation', "Children's", 'Comedy'],2:['Adventure', "Children's", 'Fantasy'],..}#电影ID 和对应的电影类型 genres_all=list() # 将每个电影的类型放在item_dict中 for item in item_ids: genres=items[items["MovieID"]==item]["Genres"].values[0].split("|") #['Animation', "Children's", 'Comedy'] self.item_dict.setdefault(item,[]).extend(genres) #{1: ['Animation', "Children's", 'Comedy']} genres_all.extend(genres) #extend() 函数用于在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)。 self.genres_all=set(genres_all)#去掉重复特征数据 得到18个特征{"Children's", 'Western', 'Drama', 'Musical', 'Mystery', 'Animation', 'Adventure', 'Sci-Fi', 'Romance', 'War', 'Action', 'Documentary', 'Film-Noir', 'Thriller', 'Crime', 'Comedy', 'Fantasy', 'Horror'} # 将每个电影的特征信息矩阵存放在 self.item_matrix中 # 保存dict时,key只能为str,所以这里对item id做str()转换 self.item_matrix={}#{'1': [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], '2': [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]} for item in self.item_dict.keys(): self.item_matrix[str(item)]=[0] * len(set(self.genres_all)) #创建一个 key为item电影ID,value 为长度为18初始值为0的数组 的数据字典{'1': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]} for genre in self.item_dict[item]: index=list(set(genres_all)).index(genre)#找到类型为例如'Animation'在genres_all所有类型集合中的位置(index) self.item_matrix[str(item)][index]=1 #把对应 value 数值下标为5的值 0换成1 #[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0]离散型One——Hot编码 json.dump(self.item_matrix, open('data/item_profile.json','w')) print("item 信息计算完成,保存路径为:{}" .format('data/item_profile.json'))

3.计算用户的偏好矩阵

# 计算用户的偏好矩阵 def prepare_user_profile(self,file='data/ratings.csv'): users = pd.read_csv(file)#users:UserID,MovieID,Rating,Timestamp user_ids = set(users["UserID"].values)#遍历用户UserId # 将users信息转化成dict users_rating_dict={} #{'UserId': {item1 :rate1,item2 :rate2}, '2': {}, '3': {},....} for user in user_ids: users_rating_dict.setdefault(str(user),{})#{'1': {}} with open(file,"r") as fr:#无异常读文件 for line in fr.readlines():#读每一行 if not line.startswith("UserID"):#去除第一行文字 (user,item,rate)=line.split(",")[:3] users_rating_dict[user][item]=int(rate)#把 截取userId作为key value (item :rate){1:{'1193': 5, '661': 3}} # 获取用户对每个类型下都有哪些电影进行了评分 self.user_matrix={} # 遍历每个用户 for user in users_rating_dict.keys(): print("user is {}".format(user)) score_list=users_rating_dict[user].values() # 用户的平均打分 avg=sum(score_list)/len(score_list) self.user_matrix[user]=[] # 遍历每个类型(保证item_profile和user_profile信息矩阵中每列表示的类型一致) for genre in self.genres_all: #依次遍历每一个类型 score_all=0.0 score_len=0 # 遍历每个item for item in users_rating_dict[user].keys():#遍历 用户1的电影Id列表 # 判断类型是否在用户评分过的电影里 if genre in self.item_dict[int(item)]: #并判断这个电影类型 是否在这个item的描述类型中 score_all += (users_rating_dict[user][item]-avg) #计算用户1对某一电影类型偏好程度公式 #把所有用户看过这个类型的电影 依次评分与平均分相减 和除以评分该类型电影总数 score_len+=1 if score_len==0:#用户无评分该类型电影 self.user_matrix[user].append(0.0) else: self.user_matrix[user].append(score_all / score_len) #把所有用户看过这个类型的电影 依次评分与平均分相减 和除以评分该类型电影总数 json.dump(self.user_matrix, open('data/user_profile.json', 'w')) print("user 信息计算完成,保存路径为:{}" .format('data/user_profile.json'))

5.模型训练(无监督学习) 计算用户与Item的喜好程度

# coding: utf-8 -*- """ Author: sunchang 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("data/item_profile.json","r")) self.user_profile=json.load(open("data/user_profile.json","r")) # 获取用户未进行评分的item列表 def get_none_score_item(self,user): items=pd.read_csv("data/movies.csv")["MovieID"].values data = pd.read_csv("data/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): #通过余弦相似度 #Uia 分子 Ua(用户对电影的偏好矩阵) Ia(电影类型的特征信息矩阵)电影shi否属于类型a Uia=sum( np.array(self.user_profile[str(user)]) * np.array(self.item_profile[str(item)]) ) Ua=math.sqrt( sum( [ math.pow(one,2) for one in self.user_profile[str(user)]] ) )#分母 Ua Ia=math.sqrt( sum( [ math.pow(one,2) for one in self.item_profile[str(item)]] ) )#分母 Ia return Uia / (Ua * Ia)

6.为用户进行电影推荐

# 为用户进行电影推荐 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) #获取用户对Item的喜好程度集合 if self.K is None:#如果前K个不是空 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)

7.推荐系统效果评估

# 推荐系统效果评估 def evaluate(self): evas=[] data = pd.read_csv("data/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("data/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) if __name__=="__main__": cb=CBRecommend(K=10) cb.recommend(1) print(cb.evaluate())


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3