首页 > 其他分享 >基于图神经网络的电商购买预测

基于图神经网络的电商购买预测

时间:2023-07-26 17:36:19浏览次数:35  
标签:基于 self torch item 神经网络 128 电商 data id

目录

本文把每一件商品看做一个点,session_id表示用户,每个用户的浏览购买物品形成一张图。把每个点都embedding成128维的向量,构建网络结构(其中利用TopKPooling对图做下采样),一个图做一个分类结果,判断买没买(0/1)。

1.查看数据

(1)数据介绍

from sklearn.preprocessing import LabelEncoder
import pandas as pd
 
df = pd.read_csv('yoochoose-clicks.dat', header=None)#yoochoose-clicks:表示用户的浏览行为
df.columns=['session_id','timestamp','item_id','category']#session_id相同表示同一用户,item_id表示所浏览的商品
 
buy_df = pd.read_csv('yoochoose-buys.dat', header=None)#yoochoose-buys描述了他最终是否会购买
buy_df.columns=['session_id','timestamp','item_id','price','quantity']
 
item_encoder = LabelEncoder()
df['item_id'] = item_encoder.fit_transform(df.item_id)#根据item_id可以在向量表中查询,转换成向量(这个过程即embedding)
df.head()#查看前5个数据

(2)选择部分数据建模

import numpy as np
#数据有点多,咱们只选择其中一小部分来建模
sampled_session_id = np.random.choice(df.session_id.unique(), 100000, replace=False)#随机取一部分数据
df = df.loc[df.session_id.isin(sampled_session_id)]
df.nunique()

(3)合并两个表

df['label'] = df.session_id.isin(buy_df.session_id)#合并两个表,把第二个表的label加入第一个表。label:False表示没买,Ture表示买了
df.head()

2.构建自己的数据集

  • 把每一个session_id都当作一个图,每一个图具有多个点和一个标签
  • 其中每个图中的点就是其item_id,特征咱们暂且用其id来表示,之后会做embedding
#如何构建数据集
from torch_geometric.data import InMemoryDataset
from tqdm import tqdm#进度条
 
class YooChooseBinaryDataset(InMemoryDataset):
    def __init__(self, root, transform=None, pre_transform=None):#构造函数
        super(YooChooseBinaryDataset, self).__init__(root, transform, pre_transform) # transform就是数据增强,对每一个数据都执行
        self.data, self.slices = torch.load(self.processed_paths[0])
 
    @property
    def raw_file_names(self): #检查self.raw_dir目录下是否存在raw_file_names()属性方法返回的每个文件 
                              #如有文件不存在,则调用download()方法执行原始文件下载
        return []
    @property
    def processed_file_names(self): #检查self.processed_dir目录下是否存在self.processed_file_names属性方法返回的所有文件,没有就会走process
        return ['yoochoose_click_binary_1M_sess.dataset']
 
    def download(self):
        pass
    
    def process(self):#没有yoochoose_click_binary_1M_sess.dataset文件时,执行该函数
        
        data_list = []
 
        # process by session_id
        grouped = df.groupby('session_id')
        for session_id, group in tqdm(grouped):#遍历每一组session_id(每一个图),目的是将其制作成(from torch_geometric.data import Data)格式
            sess_item_id = LabelEncoder().fit_transform(group.item_id)#将item_id转换成sess_item_id,从0开始。对每一组session_id中的所有item_id进行编码(例如15453,3651,15452)就按照数值大小编码成(2,0,1),索引是从0开始的
            group = group.reset_index(drop=True)
            group['sess_item_id'] = sess_item_id
            node_features = group.loc[group.session_id==session_id,['sess_item_id','item_id']].sort_values('sess_item_id').item_id.drop_duplicates().values#item_id作为node_features
 
            node_features = torch.LongTensor(node_features).unsqueeze(1)
            target_nodes = group.sess_item_id.values[1:]#构建邻接矩阵,第二个到最后一个(点的特征就由其ID组成,edge_index是这样,因为咱们浏览的过程中是有顺序的比如(0,0,2,1)
- 5.所以边就是0->0,0->2,2->1这样的,对应的索引就为target_nodes: [0 2 1],source_nodes: [0 0 2])
            source_nodes = group.sess_item_id.values[:-1]#第一个到倒数第二个
 
            edge_index = torch.tensor([source_nodes, target_nodes], dtype=torch.long)#传入形成二维邻接矩阵
            x = node_features
 
            y = torch.FloatTensor([group.label.values[0]])
 
            data = Data(x=x, edge_index=edge_index, y=y)#传入参数,构建data
            data_list.append(data)#每一个图都放入data_list
        
        data, slices = self.collate(data_list)#转换成可以保存到本地的格式
        torch.save((data, slices), self.processed_paths[0])#保存数据
dataset = YooChooseBinaryDataset(root='data/') #指定保存名字和路径

3.构建网络结构

(1)TopKPooling流程

  • 对图做下采样。其实就是对图进行剪枝操作,选择分低的节点剔除掉,然后再重新组合成一个新的图

  • 输入是x(4个点,每个点是一个5维向量),邻接矩阵A。对X乘上一组可学习的权重参数矩阵P,得到每个点的得分Y,从而筛掉得分低的点(TopK,K表示保留点的个数),对于A,关于筛掉的点的边全部去掉,达到下采样的目的。y`表示乘上各自的得分,使重要的点更重要。

(2)构建网络模型

#构建网络结构,一个图做一个分类结果,判断买没买(0/1)
embed_dim = 128
from torch_geometric.nn import TopKPooling,SAGEConv
from torch_geometric.nn import global_mean_pool as gap, global_max_pool as gmp
import torch.nn.functional as F
class Net(torch.nn.Module): #针对图进行分类任务
    def __init__(self):
        super(Net, self).__init__()
 
        self.conv1 = SAGEConv(embed_dim, 128)#卷积层,SAGEConv:重构的特征=自己*权重+邻居特征*权重
        self.pool1 = TopKPooling(128, ratio=0.8)#TopKPooling下采样,比例值
        self.conv2 = SAGEConv(128, 128)
        self.pool2 = TopKPooling(128, ratio=0.8)
        self.conv3 = SAGEConv(128, 128)
        self.pool3 = TopKPooling(128, ratio=0.8)
        self.item_embedding = torch.nn.Embedding(num_embeddings=df.item_id.max() +10, embedding_dim=embed_dim)#每个id做成128维向量
        self.lin1 = torch.nn.Linear(128, 128)#全连接
        self.lin2 = torch.nn.Linear(128, 64)#全连接
        self.lin3 = torch.nn.Linear(64, 1)#全连接
        self.bn1 = torch.nn.BatchNorm1d(128)
        self.bn2 = torch.nn.BatchNorm1d(64)
        self.act1 = torch.nn.ReLU()
        self.act2 = torch.nn.ReLU()        
  
    def forward(self, data):
        x, edge_index, batch = data.x, data.edge_index, data.batch # x:n*1,其中每个图里点的个数是不同的
        #print(x)
        x = self.item_embedding(x)# n*1*128 特征编码后的结果,每个点做成128维向量
        #print('item_embedding',x.shape)#[212, 1, 128]
        x = x.squeeze(1) # n*128        
        #print('squeeze',x.shape)#[212, 128]
        x = F.relu(self.conv1(x, edge_index))#卷积 n*128,传入点和边做更新
        #print('conv1',x.shape)
        x, edge_index, _, batch, _, _ = self.pool1(x, edge_index, None, batch)#池化pool之后得到 n*0.8个点
        #print('self.pool1',x.shape)
        #print('self.pool1',edge_index)
        #print('self.pool1',batch)
        x1 = torch.cat([gmp(x, batch), gap(x, batch)], dim=1)
        x1 = gap(x, batch)#global_mean_pool,全局平均池化,把图中的n个点的128维向量相加再除以n,最后得到1个全局的128维向量
        #print('gmp',gmp(x, batch).shape) # batch*128
        #print('cat',x1.shape) # batch*256
        x = F.relu(self.conv2(x, edge_index))#卷积
        #print('conv2',x.shape)
        x, edge_index, _, batch, _, _ = self.pool2(x, edge_index, None, batch)#池化
        #print('pool2',x.shape)
        #print('pool2',edge_index)
        #print('pool2',batch)
        x2 = torch.cat([gmp(x, batch), gap(x, batch)], dim=1)
        x2 = gap(x, batch)
        #print('x2',x2.shape)
        x = F.relu(self.conv3(x, edge_index))#卷积
        #print('conv3',x.shape)
        x, edge_index, _, batch, _, _ = self.pool3(x, edge_index, None, batch)#池化
        #print('pool3',x.shape)
        x3 = torch.cat([gmp(x, batch), gap(x, batch)], dim=1)
        x3 = gap(x, batch)
        #print('x3',x3.shape)# batch * 256
        x = x1 + x2 + x3 # 获取不同尺度的全局特征,128维
 
        x = self.lin1(x)#全连接
        #print('lin1',x.shape)
        x = self.act1(x)
        x = self.lin2(x)#全连接
        #print('lin2',x.shape)
        x = self.act2(x)      
        x = F.dropout(x, p=0.5, training=self.training)
 
        x = torch.sigmoid(self.lin3(x)).squeeze(1)#batch个结果,全连接
        #print('sigmoid',x.shape)
        return x

4.模型训练

from torch_geometric.loader import DataLoader

def train():#训练
    model.train()
 
    loss_all = 0
    for data in train_loader:#遍历
        data = data#拿到每个数据
        #print('data',data)
        optimizer.zero_grad()
        output = model(data)#传入数据
        label = data.y#拿到标签
        loss = crit(output, label)#计算损失
        loss.backward()#反向传播
        loss_all += data.num_graphs * loss.item()
        optimizer.step()#梯度更新
    return loss_all / len(dataset)
    
model = Net()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
crit = torch.nn.BCELoss()
train_loader = DataLoader(dataset, batch_size=64)
for epoch in range(10):
    print('epoch:',epoch)
    loss = train()
    print(loss)

5.结果

#计算准确率
from  sklearn.metrics import roc_auc_score

def evalute(loader,model):
    model.eval()

    prediction = []
    labels = []

    with torch.no_grad():
        for data in loader:
            data = data#.to(device)
            pred = model(data)#.detach().cpu().numpy()

            label = data.y#.detach().cpu().numpy()
            prediction.append(pred)
            labels.append(label)
    prediction =  np.hstack(prediction)
    labels = np.hstack(labels)

    return roc_auc_score(labels,prediction) 

for epoch in range(1):
    roc_auc_score = evalute(dataset,model)
    print('roc_auc_score',roc_auc_score)

标签:基于,self,torch,item,神经网络,128,电商,data,id
From: https://www.cnblogs.com/lushuang55/p/17582746.html

相关文章

  • 基于boost服务器逻辑层设计
    服务器架构设计通常的Session(会话层)  Asio底层的通信过程,如下图实际服务器结优化的架构如下具体逻辑可以查看:  https://llfc.club/category?catid=225RaiVNI8pFDD5L4m807g7ZwmF#!aid/2QbUASZ5jV8jgKYFngRHrG8pu7z代码如下:const.h#pragmaonce#defineMAX_LENGT......
  • 基于LSTM深度学习网络的人员行走速度识别matlab仿真,以第一视角视频为样本进行跑或者
    1.算法理论概述      人员行走速度是衡量人体运动能力和身体健康的重要指标之一。目前,常见的人员行走速度识别方法主要基于传感器或摄像头获取的数据,如加速度计数据、GPS数据和视频数据等等。其中,基于视频数据的方法因为其易于获取和处理而备受关注。但是,传统的基于特征提......
  • 基于Hologres向量计算与大模型免费定制专属聊天机器人
    简介:本文为您介绍如何基于Hologres向量计算能力,结合大模型的阅读理解和信息整合能力,对该垂直行业的问题提供更贴切的回答,即费、快速定制专属聊天机器人。背景信息大模型可以广泛应用于各行各业。使用大模型定制聊天机器人,除了训练大模型的方式外,还可以使用提示词微调(Prompt-tuning)......
  • 最新基于nonebot的qq机器人搭建
    导读核心资源(参考各项目到各自release下载NoneBot简介|go-cqhttp帮助中心qq登录需要包签名,要自己部署https://github.com/fuqiuluo/unidbg-fetch-qsign环境ubuntu:win10商店直接下个ubuntu做wsl,python:wsl里面安装conda,conda创建虚拟环境使用python最新3.11java......
  • 基于 Android 的旅游电商应用系统设计与实现-计算机毕业设计源码+LW文档
    开题申请(包括选题目的意义、研究现状、成果提纲、文献综述、创新思路、参考文献,篇幅不够可另加页)1.开题依据1.1研究的目的意义伴随着智能终端的高速发展,移动互联网与传统旅游业开始了加速融合,如今的旅游业已经得到了蓬勃发展。用户只需要一台移动终端,就能够随时随地的掌握各类旅......
  • 基于微信小程序的校园设备报修平台的设计与实现-计算机毕业设计源码+LW文档
    【摘要】随着互联网技术的发发展,计算机技术广泛应用在人们的生活中,逐渐成为日常工作、生活不可或缺的工具。在高校,各种管理系统层出不穷,为校园设备报修管理开发必要的系统,能够有效的提升管理效率。一直以来,校园设备报修一直没有进行系统化的管理,学生无法快速进行报修,由此提出开发基......
  • 基于Android的眼镜商场app-计算机毕业设计源码+LW文档
    前端用户功能:(1)app首页:显示app所有商品的相关信息,供用户搜索、浏览查看,包括商品展示、商品类别及搜索等信息的展示。(2)注册登录:实现用户注册,登录系统实现,注册成功之后默认为登录状态。(3)商品展示:商家可以制作漂亮的眼镜产品图片,并在商场展示。用户可以通过查看图片细节来......
  • m基于16QAM软解调和LDPC信道编译码的通信链路误码率仿真
    1.算法仿真效果matlab2022a仿真结果如下:   2.算法涉及理论知识概要基于16QAM软解调和LDPC信道编译码的通信链路包括以下主要步骤: 2.1数据源编码       在数据源编码阶段,输入的二进制数据会被编码为纠错码,以提高数据传输的可靠性。常用的纠错码包括卷积码、L......
  • 基于深度学习的图像分割技术探究
    导言:图像分割是计算机视觉领域的重要任务,旨在将图像划分为不同的语义区域,实现对图像中感兴趣物体的定位和提取。深度学习作为图像分割的新兴技术,通过卷积神经网络(CNN)等模型,取得了显著的分割效果。本文将探究基于深度学习的图像分割技术的原理、应用以及面临的挑战。第一部分:基于......
  • 我开源了团队内部基于SpringBoot Web快速开发的API脚手架v1.6.0更新
    什么是rest-api-spring-boot-starterrest-api-spring-boot-starter适用于SpringBootWebAPI快速构建让开发人员快速构建统一规范的业务RestFullAPI不在去关心一些繁琐。重复工作,而是把重点聚焦到业务。动机每次WebAPI常用功能都需要重新写一遍。或者复制之前的项目代码......