06、基于内容的过滤算法Tensorflow实现

06、基于内容的过滤算法Tensorflow实现

开始学习机器学习啦,已经把吴恩达的课全部刷完了,现在开始熟悉一下复现代码。全部工程可从最上方链接下载。

05、基于梯度下降的协同过滤算法中已经介绍了协同过滤算法的基本实现方法,但是这种方法仅根据用户的相似度进行推荐,而不关注用户或者电影本身的一些特征的匹配,基于内容的过滤算法正式为了对此进行改进。

此处还是以电影推荐作为实际的案例

1、基于内容的过滤算法实现原理

基于内容的过滤算法的神经网络实现依赖于现有的特征数据,这个特征数据包括用户的特征数据电影本身的特征数据。常理来讲,最终的打分结果是用户自身的特征和电影本身的属性共同决定的,但是其互相影响的机制可能并不明确,因此可以使用如下的神经网络模型直接训练得到结果:
在这里插入图片描述
对于上图,在吴恩达的解释中,Vu和Vm分别是用户和电影的特征向量,这个特征是从原有的基础数据(如电影类型、用户爱好、用户年龄等等)中训练出来的,其并没有具体对应的特征含义

因此,其所介绍的基于内容的过滤算法完全基于神经网络的模型得到预测的打分结果,进而进行推荐,下面对原理步骤进行解释。

2、数据集的简单解释

全部的工程文件可以在最上方的链接进行下载。这个数据集的来源是:dataset,吴恩达老师的数据在此基础上进行了二元化的处理,所以看着非常难以理解。

首先是content_user_train.csv这个文件,,其抬头在content_user_train_header.txt中将其组合即可得到用户的数据,如下所示:
在这里插入图片描述
但是值得注意的是,数据和很多的重复的,例如对于用户3,其第40-43行都是一样的数据,可以看到用户3给一个电影打过分:
在这里插入图片描述
而这代表用户3看过的电影在content_item_train.csv这个文件的第40-43行,可以看到只有72378这个代号的电影,这个电影占用四行,代表它在四个分类(比如爱情、浪漫、动作等等),电影的平均分是2.6。
在这里插入图片描述
content_item_train.csv这个文件的抬头在content_item_train_header.txt中,将其组合即可得到电影的数据,例如:
在这里插入图片描述

为充分解释,再举一个用户2的例子,其重复占用从第1行到第39行:
在这里插入图片描述
而在content_item_train.csv这个文件中的第1行到第39行,表示其看过6874、8798、46970等16个电影,每个电影属于多少个分类,每个电影就会占用多少行(6874占用3个分类就有三行):
在这里插入图片描述

content_item_train.csv中的电影会有重复,毕竟可能不同用户都给同一电影打分,因此6874除了第一行有第474行也有,这么设计只是为了查找时方便对应,但是训练速度估计比较着急
在这里插入图片描述
content_item_vecs.csv这里面存储的也是电影的相关原始特征,但是其不会出现上面的重复,因为其不需要和用户对应且电影id递增排列。
在这里插入图片描述
content_movie_list.csv这里面是id所对应的实际电影:
在这里插入图片描述

3、基于内容的过滤算法实现步骤

STEP1: 引入包并加载数据集(不考虑用户ID、评分次数和平均评分、电影ID,所以需要移除部分数据):

from keras import Model
import pandas as pd
import tensorflow as tf
from tensorflow import keras
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from sklearn.model_selection import train_test_split
from Content_Based_Filtering_recsysNN_utils import *
pd.set_option("display.precision", 1)# 加载数据,设置配置变量
item_train, user_train, y_train, item_features, user_features, item_vecs, movie_dict, user_to_genre = load_data()
# 计算用户特征的数量,训练时移除用户ID、评分次数和平均评分
num_user_features = user_train.shape[1] - 3
# 计算物品特征的数量,训练时移除电影ID
num_item_features = item_train.shape[1] - 1
# 用户向量的起始位置
uvs = 3
# 物品向量的起始位置
ivs = 3
# 在训练中使用的用户列的起始位置
u_s = 3
# 在训练中使用的物品列的起始位置
i_s = 1

STEP2: 数据标准化与测试集的分割:

# 如果为True,则对数据应用标准化
scaledata = True
# 归一化训练数据
if scaledata:# 保存原始的item_train和user_train数据item_train_save = item_trainuser_train_save = user_train# 对item_train数据进行标准化处理scalerItem = StandardScaler()scalerItem.fit(item_train)item_train = scalerItem.transform(item_train)# 对user_train数据进行标准化处理scalerUser = StandardScaler()scalerUser.fit(user_train)user_train = scalerUser.transform(user_train)# 对y_train数据进行归一化处理,使其值在-1到1之间scaler = MinMaxScaler((-1, 1))scaler.fit(y_train.reshape(-1, 1))y_train = scaler.transform(y_train.reshape(-1, 1))# 使用train_test_split函数将数据集分割为训练集和测试集,其中训练集占比为80%
item_train, item_test = train_test_split(item_train, train_size=0.80, shuffle=True, random_state=1)
user_train, user_test = train_test_split(user_train, train_size=0.80, shuffle=True, random_state=1)
y_train, y_test = train_test_split(y_train, train_size=0.80, shuffle=True, random_state=1)# 打印训练集和测试集的形状
print(f"movie/item training data shape: {item_train.shape}")
print(f"movie/item test  data shape: {item_test.shape}")

STEP3: 模型构建与训练(其中特征数量num_outputs 指的是训练最终得到的特征数量,即Vu和Vm的维度,理论上可以随意选取):

# 构建模型  
# 输出的电影特征和用户特征数量,都是32  
num_outputs = 32  
tf.random.set_seed(1)  # 设置随机种子以确保结果的可复现性  # 定义用户神经网络  
user_NN = tf.keras.models.Sequential([  tf.keras.layers.Dense(256, activation='relu'),  # 第一层有256个神经元,使用ReLU激活函数  tf.keras.layers.Dense(128, activation='relu'),  # 第二层有128个神经元,使用ReLU激活函数  tf.keras.layers.Dense(num_outputs),            # 输出层有32个神经元  
])  # 定义物品神经网络  
item_NN = tf.keras.models.Sequential([  tf.keras.layers.Dense(256, activation='relu'),  # 第一层有256个神经元,使用ReLU激活函数  tf.keras.layers.Dense(128, activation='relu'),  # 第二层有128个神经元,使用ReLU激活函数  tf.keras.layers.Dense(num_outputs),            # 输出层有32个神经元  
])  # 创建用户输入并连接到基础网络  
input_user = tf.keras.layers.Input(shape=(num_user_features))  # 定义用户输入层  
vu = user_NN(input_user)  # 将用户输入传入用户神经网络  
vu = tf.linalg.l2_normalize(vu, axis=1)  # 对用户向量进行L2正则化  # 创建物品输入并连接到基础网络  
input_item = tf.keras.layers.Input(shape=(num_item_features))  # 定义物品输入层  
vm = item_NN(input_item)  # 将物品输入传入物品神经网络  
vm = tf.linalg.l2_normalize(vm, axis=1)  # 对物品向量进行L2正则化  # 计算两个向量vu和vm的点积  
output = tf.keras.layers.Dot(axes=1)([vu, vm])  # 计算点积作为输出  # 指定模型的输入和输出  
model = Model([input_user, input_item], output)  # 定义模型  
model.summary()  # 打印模型概要  # 设置模型的优化器和损失函数  
tf.random.set_seed(1)  
cost_fn = tf.keras.losses.MeanSquaredError()  # 使用均方误差作为损失函数  
opt = keras.optimizers.Adam(learning_rate=0.01)  # 使用Adam优化器,学习率为0.01  
model.compile(optimizer=opt, loss=cost_fn)  # 编译模型  # 训练模型  
tf.random.set_seed(1)  
model.fit([user_train[:, u_s:], item_train[:, i_s:]], y_train, epochs=20)  # 对模型进行20轮训练  # 评估模型在测试集上的表现  
model.evaluate([user_test[:, u_s:], item_test[:, i_s:]], y_test)  # 计算模型在测试集上的损失值

STEP4: 基于模型的新用户最佳推荐

首先要构建新用户的特征:

# 给新用户推荐
new_user_id = 5000
new_rating_ave = 1.0
new_action = 5
new_adventure = 1
new_animation = 1
new_childrens = 5
new_comedy = 1
new_crime = 5
new_documentary = 1
new_drama = 1
new_fantasy = 1
new_horror = 1
new_mystery = 1
new_romance = 1
new_scifi = 5
new_thriller = 1
new_rating_count = 1user_vec = np.array([[new_user_id, new_rating_count, new_rating_ave,new_action, new_adventure, new_animation, new_childrens,new_comedy, new_crime, new_documentary,new_drama, new_fantasy, new_horror, new_mystery,new_romance, new_scifi, new_thriller]])

下面是基于新用户特征、所有的电影特征和现有模型进行预测:

# generate and replicate the user vector to match the number movies in the data set.
user_vecs = gen_user_vecs(user_vec,len(item_vecs))# 进行预测并按照推荐程度进行排序
sorted_index, sorted_ypu, sorted_items, sorted_user = predict_uservec(user_vecs,  item_vecs, model, u_s, i_s,scaler, scalerUser, scalerItem, scaledata=scaledata)
# 打印结果
print_pred_movies(sorted_ypu, sorted_user, sorted_items, movie_dict, maxcount = 10)

其中预测函数中需要先进行归一化,如何进行预测:

def predict_uservec(user_vecs, item_vecs, model, u_s, i_s, scaler, ScalerUser, ScalerItem, scaledata=False):  """  给定一个用户向量,对item_vecs中的所有电影进行预测,返回一个按预测评分排序的数组预测值,  以及按预测评分排序索引排序的用户和物品数组。  """  # 判断是否需要缩放数据  if scaledata:  # 如果需要缩放,则使用ScalerUser和ScalerItem对user_vecs和item_vecs进行缩放  scaled_user_vecs = ScalerUser.transform(user_vecs)  scaled_item_vecs = ScalerItem.transform(item_vecs)  # 使用缩放后的数据进行预测  y_p = model.predict([scaled_user_vecs[:, u_s:], scaled_item_vecs[:, i_s:]])  else:  # 如果不需要缩放,则直接使用原始数据进行预测  y_p = model.predict([user_vecs[:, u_s:], item_vecs[:, i_s:]])  # 使用scaler对预测结果进行逆变换  y_pu = scaler.inverse_transform(y_p)  # 检查预测结果中是否有负数,如果有则打印错误信息  if np.any(y_pu < 0):   print("Error, expected all positive predictions")  # 对预测结果进行排序,获取排序索引,并按照排序索引对预测结果、物品和用户进行排序  sorted_index = np.argsort(-y_pu, axis=0).reshape(-1).tolist()  # 取反以获得最高评分在前  sorted_ypu = y_pu[sorted_index]  sorted_items = item_vecs[sorted_index]  sorted_user = user_vecs[sorted_index]  # 返回排序索引、排序后的预测结果、排序后的物品和用户  return (sorted_index, sorted_ypu, sorted_items, sorted_user)

4、结果分析

按照我给出的新用户的特性:action、childrens、crime、scifi是其比较喜欢的,推荐的排名前十的电影如下:
在这里插入图片描述
可以看到其推荐的东西也比较符合这些特征。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/196643.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot集成i18n(多语言)

配置文件 spring: messages: basename: il8n/messages # 配置国际化资源文件路径 fallback-to-system-locale: true # 是否使用系统默认的语言环境作为备选项 国际化配置 import org.springframework.context.annotation.Bean; import org.spr…

MySQL-宋红康-(课P14-P15)-基本查询语句(Select)

b站视频&#xff1a; 14-最基本的SELECT...FROM结构_哔哩哔哩_bilibili 8.4 基本查询(Select)语句 数据table: emp员工表创建如下 # 员工表 CREATE TABLE EMP (EMPNO INT PRIMARY KEY, -- 员工编号ENAME VARCHAR(10), -- 员工名称JOB VARCHAR(9), -- 工…

10、SQL注入——数据库基础

文章目录 一、数据库概述二、数据库分类Mysql数据库连接方法 三、识别数据库四、SQL语法4.1 SQL基本语法4.2 高级操作 一、数据库概述 数据库&#xff08;database&#xff09;&#xff1a;存储在磁盘、磁带、光盘或其他外存介质上、按一定结构组织在一起的相关数据的集合。数…

龙迅分配器LT86102UXE/LT86104UX,HDMI一分二/HDMI一分四

龙迅LT86102UXE描述; Lontium LT86102UXE HDMI2.0分配器具有1&#xff1a;2的分配器&#xff0c;符合HDMI2.0/1.4规范&#xff0c;最大6Gbps高速数据速率&#xff0c;自适应均衡RX输入和预先强调的TX输出&#xff0c;以支持长电缆应用程序&#xff0c;内部TX通道交换灵活的PCB…

部分c++11特性介绍

在2003年C标准委员会曾经提交了一份技术勘误表(简称TC1)&#xff0c;使得C03这个名字已经取代了C98称为C11之前的最新C标准名称。不过由于C03(TC1)主要是对C98标准中的漏洞进行修复&#xff0c;语言的核心部分则没有改动&#xff0c;因此人们习惯性的把两个标准合并称为C98/03标…

Day50力扣打卡

打卡记录 三个无重叠子数组的最大和 链接 滑动窗口 class Solution:def maxSumOfThreeSubarrays(self, nums: List[int], k: int) -> List[int]:n, ans len(nums), []sum1 sum2 sum3 0maxsum1idx, maxsum12idx 0, ()maxsum1 maxsum12 total 0for i in range(2 * …

01 高等数学.武忠祥.0基础

第一章 函数与极限 01映射与函数 02 函数概念 对应法则 定义域 常见函数 函数的几种特性 周期函数不一定有最小周期。 涉及额外与复习 存在与任意的关系

MYSQL练题笔记-高级查询和连接-简单题3题

写了下面的前3道题。 一、每位经理的下属员工数量 看到题目就知道和之前的至少有5名下属的经理很相似&#xff0c;嘿嘿写对了就不做过多的讲解了。 二、员工的直属部门相关表和题目如下 刚开始觉得很简单&#xff0c;但是仔细想想这道题有两个输出&#xff0c;觉得想不出来&a…

C语言数组(上)

# 数组的概念 数组是一组相同类型元素的集合。数组中存放的是一个或多个数据&#xff0c;但是数组中的元素个数不能为零&#xff1b;数组中存放的所有元素&#xff08;数据&#xff09;的类型必须是相同的。 数组分为一维数组和多维数组&#xff0c;多维数组一般比较多见的是二…

跨域问题与解决-gatway

3.6.1.什么是跨域问题 跨域&#xff1a;域名不一致就是跨域&#xff0c;主要包括&#xff1a; 域名不同&#xff1a; www.taobao.com 和 www.taobao.org 和 www.jd.com 和 miaosha.jd.com域名相同&#xff0c;端口不同&#xff1a;localhost:8080和localhost8081 跨域问题&a…

ADB命令集锦,一起来学吧

前言 在测试APP时&#xff0c;我们常常会用到adb命令来协助测试&#xff0c;那么adb命令到底是什么&#xff1f;有什么用&#xff1f;怎么用&#xff1f; 今天我就整理了一些工作中常用的adb知识点&#xff0c;希望对大家有所帮助。 ADB学习全攻略 ADB是什么&#xff1f; a…

三种定时器的实现方式

一、Scheduled Schedule是Spring框架提供的一种简单的定时任务调度方法&#xff0c;通过注解的方式即可实现定时任务的调度。它适用于简单的定时任务需求&#xff0c;例如每隔一段时间执行一次任务或者在特定时间执行任务。Scheduled可以轻松地集成到Spring应用中&#xff0c;…

LangChain的函数,工具和代理(四):使用 OpenAI 函数进行标记(Tagging) 提取(Extraction)

在上一篇博客LangChain中轻松实现OpenAI函数调用 中我们学习了如何使用Pydantic来生成openai的函数描述对象&#xff0c;并且通过在langchain中调用Pydantic生成的函数描述变量来轻松实现openai的函数调用功能&#xff0c;在此基础上今天我们再介绍两个非常实用的功能&#xff…

2024年,Rust和Go学哪个更好?

Rust vs. Go&#xff0c;在2024年&#xff0c;应该选择哪一个&#xff1f;或者说应该选择哪种语言——GoLang还是Rust。这可能是许多程序员在选择语言时考虑的一个问题。选择理想的编程语言被视为在这个不断变化的环境中取得成功的重要抉择。 GoLang和Rust是当今使用的最年轻的…

【黑马甄选离线数仓day08_会员主题域开发】

1. 会员主题域需求说明 1.1 各类会员数量统计 说明&#xff1a;公司为了对不同会员进行不同的营销策略&#xff0c;对各类会员的数量都非常敏感&#xff0c;比如注册会员、消费会员、复购会员、活跃会员、沉睡会员。不仅需要看新增数量还要看累积数量。 指标&#xff1a;新增…

二十九、微服务案例完善(数据聚合、自动补全、数据同步)

目录 一、定义 二、分类 1、桶(Bucket)聚合: 2、度量(Metric&#xff09;聚合: 3、管道聚合&#xff08;Pipeline Aggregation&#xff09;&#xff1a; 4、注意&#xff1a; 参与聚合的字段类型必须是: 三、使用DSL实现聚合 聚合所必须的三要素&#xff1a; 聚合可配…

考研数学 每日一题

考研数学 每日一题

【Linux】初识云服务器 -- 使用 XShell 远程登录 Linux

Linux 是一款企业级后台操作系统&#xff0c;命令行方式交互&#xff0c;开源。 搭建属于自己的 Linux 服务器&#xff1a;我是直接选择购买的腾讯云轻量级服务器&#xff08;CentOS 7.6&#xff09;&#xff0c;不贵又相对方便&#xff0c;可以直接上手使用&#xff0c;不需要…

Elasticsearch:为现代搜索工作流程和生成式人工智能应用程序铺平道路

作者&#xff1a;Matt Riley Elastic 的创新投资支持开放的生态系统和更简单的开发者体验。 在本博客中&#xff0c;我们希望分享 Elastic 为简化你构建 AI 应用程序的体验而进行的投资。 我们知道&#xff0c;开发人员必须在当今快速发展的人工智能环境中保持灵活性。 然而&a…

JavaEE之多线程编程(一):基础篇

文章目录 一、关于操作系统一、认识进程 process二、认识线程三、进程和线程的区别&#xff08;重点&#xff01;&#xff09;四、Java的线程和操作系统线程的关系五、第一个多线程编程 一、关于操作系统 【操作系统】 驱动程序&#xff1a; 如&#xff1a;我们知道JDBC的驱动程…