Datawhale干货

作者:阿水,北京航空航天大学,Datawhale成员

本文以CCF大数据与计算智能大赛(CCF BDCI)图书推荐系统竞赛为实践背景,使用Paddle构建用户与图书的打分模型,借助Embedding层来完成具体的匹配过程。后台回复 211208 可获取完整代码。

代码地址

https://aistudio.baidu.com/aistudio/projectdetail/2556840

实践背景

赛题背景

赛事地址

https://www.datafountain.cn/competitions/542

随着新型互联网的发展,人类逐渐进入了信息爆炸时代。新型电商网络面临的问题也逐渐转为如何让用户从海量的商品中挑选到自己想要的目标。推荐系统正是在互联网快速发展之后的产物。

为帮助电商系统识别用户需求,为用户提供其更加感兴趣的信息,从而为用户提供更好的服务,需要依据真实的图书阅读数据集,利用机器学习的相关技术,建立一个图书推荐系统。用于为用户推荐其可能进行阅读的数据,从而在产生商业价值的同时,提升用户的阅读体验,帮助创建全民读书的良好社会风气。

赛题任务

依据真实世界中的用户-图书交互记录,利用机器学习相关技术,建立一个精确稳定的图书推荐系统,预测用户可能会进行阅读的书籍。

赛题数据

数据集来自公开数据集Goodbooks-10k,包含网站Goodreads中对10,000本书共约6,000,000条评分。为了预测用户下一个可能的交互对象,数据集已经处理为隐式交互数据集。该数据集广泛的应用于推荐系统中。

数据文件夹包含3个文件,依次为:

  • 训练集: train.csv 训练数据集,为用户-图书交互记录

  • 测试集: test.csv 测试数据集,只有需要进行预测用户ID

  • 提交样例: submission.csv 仅有两个字段user_id/item_id

解题思路

使用深度学习模型构建隐式推荐算法模型,并构建负样本,最终按照模型输出的评分进行排序,做出最终的推荐。具体可以分为以下几个步骤:

  • 步骤1:读取数据,对用户和图书进行编码;

  • 步骤2:利用训练集构建负样本;

  • 步骤3:使用Paddle构建打分模型;

  • 步骤4:对测试集数据进行预测;

步骤1:读取数据集

首先我们使用pandas读取数据集,并对数据的字段进行编码。这里可以手动构造编码过程,也可以使用LabelEncoder来完成。

这一步骤的操作目的是将对用户和图书编码为连续的数值,原始的取值并不是连续的,这样可以减少后续模型所需要的空间。

步骤2:构建负样本

由于原始训练集中都是记录的是用户已有的图书记录,并不存在负样本。而在预测阶段我们需要预测用户下一个图书,此时的预测空间是用户对所有图书的关系。

这里构建负样本的操作非常粗暴,直接是选择用户在训练集中没有图书。这里可以先使用协同过滤的思路来构建负样本,即将负样本是相似用户都没有记录的图书。

步骤3:Paddle搭建打分模型

这里使用Paddle构建用户与图书的打分模型,借助Embedding层来完成具体的匹配过程。这里用最简单的dot来完成匹配,没有构建复杂的模型。

步骤4:对测试集进行预测

首先将测试集数据转为模型需要的格式,然后一行代码完成预测即可,然后转换为提交格式。

改进思路

由于现有的代码写的比较基础,所以有很多改进的步骤:

  • 对模型精度进行改进,可以考虑构建更加复杂的模型,并对训练集负样本构造过程进行改进。

  • 对模型使用内存,可以考虑使用Numpy代替Pandas的操作。

代码实践

读取数据集

# 查看当前挂载的数据集目录, 该目录下的变更重启环境后会自动还原
# View dataset directory.
# This directory will be recovered automatically after resetting environment. !unzip /home/aistudio/data/data114712/train_dataset.zip
Archive:  /home/aistudio/data/data114712/train_dataset.zipinflating: train_dataset.csv       !cp /home/aistudio/data/data114712/test_dataset.csv ./!head train_dataset.csv
user_id,item_idimport pandas as pd
import numpy as np
import paddle
import paddle.nn as nn
from paddle.io import Datasetdf = pd.read_csv('train_dataset.csv')
user_ids = df["user_id"].unique().tolist()user2user_encoded = {x: i for i, x in enumerate(user_ids)}
userencoded2user = {i: x for i, x in enumerate(user_ids)}book_ids = df["item_id"].unique().tolist()
book2book_encoded = {x: i for i, x in enumerate(book_ids)}
book_encoded2book = {i: x for i, x in enumerate(book_ids)}df["user"] = df["user_id"].map(user2user_encoded)
df["movie"] = df["item_id"].map(book2book_encoded)num_users = len(user2user_encoded)
num_books = len(book_encoded2book)user_book_dict = df.iloc[:].groupby(['user'])['movie'].apply(list)user_book_dict
user

构造负样本

neg_df = []
book_set = set(list(book_encoded2book.keys()))
for user_idx in user_book_dict.index:book_idx = book_set - set(list(user_book_dict.loc[user_idx]))book_idx = list(book_idx)neg_book_idx = np.random.choice(book_idx, 100)for x in neg_book_idx:neg_df.append([user_idx, x])neg_df = pd.DataFrame(neg_df, columns=['user', 'movie'])
neg_df['label'] = 0df['label'] = 1
train_df = pd.concat([df[['user', 'movie', 'label']], neg_df[['user', 'movie', 'label']]], axis=0)train_df = train_df.sample(frac=1)del df;

自定义数据集

# 自定义数据集# 映射式(map-style)数据集需要继承paddle.io.Dataset
class SelfDefinedDataset(Dataset):def __init__(self, data_x, data_y, mode = 'train'):super(SelfDefinedDataset, self).__init__()self.data_x = data_xself.data_y = data_yself.mode = modedef __getitem__(self, idx):if self.mode == 'predict':return self.data_x[idx]else:return self.data_x[idx], self.data_y[idx]def __len__(self):return len(self.data_x)from sklearn.model_selection import train_test_split
x_train, x_val, y_train, y_val = train_test_split(train_df[['user', 'movie']].values, train_df['label'].values.astype(np.float32).reshape(-1, 1))traindataset = SelfDefinedDataset(x_train, y_train)
for data, label in traindataset:print(data.shape, label.shape)print(data, label)breaktrain_loader = paddle.io.DataLoader(traindataset, batch_size = 1280*4, shuffle = True)
for batch_id, data in enumerate(train_loader):x_data = data[0]y_data = data[1]print(x_data.shape)print(y_data.shape)breakval_dataset = SelfDefinedDataset(x_val, y_val)
val_loader = paddle.io.DataLoader(val_dataset, batch_size = 1280*4, shuffle = True)
for batch_id, data in enumerate(val_loader):x_data = data[0]y_data = data[1]print(x_data.shape)print(y_data.shape)break

定义模型

EMBEDDING_SIZE = 32class RecommenderNet(nn.Layer):def __init__(self, num_users, num_movies, embedding_size):super(RecommenderNet, self).__init__()self.num_users = num_usersself.num_movies = num_moviesself.embedding_size = embedding_sizeweight_attr_user = paddle.ParamAttr(regularizer = paddle.regularizer.L2Decay(1e-6),initializer = nn.initializer.KaimingNormal())self.user_embedding = nn.Embedding(num_users,embedding_size,weight_attr=weight_attr_user)self.user_bias = nn.Embedding(num_users, 1)weight_attr_movie = paddle.ParamAttr(regularizer = paddle.regularizer.L2Decay(1e-6),initializer = nn.initializer.KaimingNormal())self.movie_embedding = nn.Embedding(num_movies,embedding_size,weight_attr=weight_attr_movie)self.movie_bias = nn.Embedding(num_movies, 1)def forward(self, inputs):user_vector = self.user_embedding(inputs[:, 0])user_bias = self.user_bias(inputs[:, 0])movie_vector = self.movie_embedding(inputs[:, 1])movie_bias = self.movie_bias(inputs[:, 1])dot_user_movie = paddle.dot(user_vector, movie_vector)x = dot_user_movie + user_bias + movie_biasx = nn.functional.sigmoid(x)return xmodel = RecommenderNet(num_users, num_books, EMBEDDING_SIZE)model = paddle.Model(model)
optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.003)
loss = nn.BCELoss()
metric = paddle.metric.Precision()## 设置visualdl路径
log_dir = './visualdl'
callback = paddle.callbacks.VisualDL(log_dir=log_dir)model.prepare(optimizer, loss, metric)
model.fit(train_loader, val_loader, epochs=5, save_dir='./checkpoints', verbose=1, callbacks=callback)

预测测试集

test_df = []
with open('sub.csv', 'w') as up:up.write('user_id,item_id\n')book_set = set(list(book_encoded2book.keys()))
for idx in range(int(len(user_book_dict)/1000) +1):test_user_idx = []test_book_idx = []for user_idx in user_book_dict.index[idx*1000:(idx+1)*1000]:book_idx = book_set - set(list(user_book_dict.loc[user_idx]))book_idx = list(book_idx)test_user_idx += [user_idx] * len(book_idx)test_book_idx +=  book_idxtest_data = np.array([test_user_idx, test_book_idx]).Ttest_dataset = SelfDefinedDataset(test_data, data_y=None, mode='predict')test_loader = paddle.io.DataLoader(test_dataset, batch_size=1280, shuffle = False)        test_predict = model.predict(test_loader, batch_size=1024)test_predict = np.concatenate(test_predict[0], 0)test_data = pd.DataFrame(test_data, columns=['user', 'book'])test_data['label'] = test_predictfor gp in test_data.groupby(['user']):with open('sub.csv', 'a') as up:u = gp[0]b = gp[1]['book'].iloc[gp[1]['label'].argmax()]up.write(f'{userencoded2user[u]}, {book_encoded2book[b]}\n')del test_data, test_dataset, test_loader

整理不易,三连

CCF推荐系统项目代码解读!相关推荐

  1. TPA_LSTM项目代码解读-pyrtoch

    文章目录 参考文章 导读 参数配置 读取数据 数据标准化 数据集分类 模型训练与验证 开始训练 模型向前传播 预测阶段 参考文章 论文地址 项目代码 TPA注意力机制(TPA-LSTM) 深度学习at ...

  2. MPC多旋翼控制 - 线性MPC代码解读(mav_control_rw项目)

    MPC无人机控制 - mav_control_rw项目 - 线性MPC代码解读 大型工程的代码还是得记录一下,不然每次都得回头看.紧接上篇趁热打铁一下 MPC多旋翼控制 - mav_control_r ...

  3. 200行代码解读TDEngine背后的定时器

    作者 | beyondma来源 | CSDN博客 导读:最近几周,本文作者几篇有关陶建辉老师最新的创业项目-TdEngine代码解读文章出人意料地引起了巨大的反响,原以为C语言已经是昨日黄花,不过从读 ...

  4. 优秀的 Java 项目代码都是如何分层的?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 来源:http://rrd.me/ej56f 1.背景 2.如何进 ...

  5. 基于SegNet和UNet的遥感图像分割代码解读

    基于SegNet和UNet的遥感图像分割代码解读 目录 基于SegNet和UNet的遥感图像分割代码解读 前言 概述 代码框架 代码细节分析 划分数据集gen_dataset.py UNet模型训练u ...

  6. [水力建模]EPANET代码解读1

    EPANET代码解读1 EPANET是美国环境保护局(环保署)公布的水力分析引擎,其源代码是开放的,但由于是用C写的,并且代码清晰度并不够,因此有必要解读一下. EPANET当前最新版本是2.0,可以 ...

  7. 鱼眼图像自监督深度估计原理分析和Omnidet核心代码解读

    作者丨苹果姐@知乎 来源丨https://zhuanlan.zhihu.com/p/508090405 编辑丨3D视觉工坊 在自动驾驶实际应用中,对相机传感器的要求之一是拥有尽可能大的视野范围,鱼眼相 ...

  8. 飞桨PP-HumanSeg本地实时视频推理代码解读

    文章同样发布在百度AIStudio,Fork后即可在线运行,请点击这里 本人希望基于PaddleSeg对视频实时进行图像分割,但在AiStudio中检索分割和实时两个关键词后并没有得到理想的结果,大部 ...

  9. 视觉学习笔记3——复现GSDT,且代码解读

    文章目录 一.GSDT是什么? 二.搭建GSDT 1.硬件 2.读入数据 3.搭建GSDT环境 三.报错解决: 错误一: 错误二: 四.复现: 代码解读: if __name__ == '__main ...

最新文章

  1. 大数据时代涉军网络舆情引导的“5个结合”
  2. java组长一个月工资多少,保准看明白!
  3. SameSite Cookie,防止 CSRF 攻击
  4. C |格式化输出与变量类型
  5. 字符与编码(编码转换)
  6. Linux 定时执行命令 crontab
  7. 没有bug队——加贝——Python 练习实例 11,12
  8. 了解招聘中的这些潜台词,找工作少走弯路
  9. 阻止form表单提交的常用方式
  10. Netty工作笔记0046---异步模型原理剖析
  11. Note: pdfcrop
  12. 蓝桥杯 基础练习 特殊回文数
  13. solaris 10 虚拟机下安装双机
  14. 这是阿里人手机里,这一年最舍不得删的照片
  15. Spark SQL面试题
  16. 在使用JEDate时间控件时,不能捕捉到input的change事件的解决办法
  17. win10连Android机,Windows10电脑可以和安卓手机无缝连接使用了,实用性干翻Mac-win10手机...
  18. Endnote如何添加CAJ格式文件
  19. Linux Raid0的配置
  20. ie8加载js太慢_ie8加载不了javascript怎么办?

热门文章

  1. LA3177 - Beijing Guards(二分+贪心【更优美的解法)
  2. 083 HBase的完全分布式的搭建与部署,以及多master
  3. php学习之道:WSDL具体解释(三)
  4. WebView通过loadDataWithBaseURL加载本地页面卡死
  5. 2021 线性代数 第三章 习题课
  6. 刻意练习:Python基础 -- Task09. else 与 with 语句
  7. 【PAT (Basic Level) 】1015 德才论 (25 分)
  8. delphi xe 文件服务器,DelphiXE7中创建WebService(服务端+客户端)
  9. 推荐 6 个好用到爆的 Pycharm 插件
  10. 小米AI实验室六篇论文获ICASSP2022收录,多模态语音唤醒挑战赛夺冠