Task 04 特征工程

博客探讨如何将推荐系统的问题转化为监督学习,通过构造特征和标签,利用用户历史点击行为,如文章类型、创建时间、字数等,以及文章与用户最后几次点击的相似性、时间差等特征,来预测用户的最后一次点击。介绍了数据处理步骤,包括特征构造、标签制作、数据集划分,并提及可能的特征如用户与候选item的相似性。
摘要由CSDN通过智能技术生成

1. 制作特征和标签,转成监督学习问题

我们先捋一下基于原始的给定数据,有哪些特征可以利用:\

  1. 文章的自身特征: category_id表示这文章的类型,created_at_ts表示文章建立的时间,这个变量着眼于文章的时效性,words_count是文章的字数,一般字数太长我们不太喜欢点击,也不排除有人就喜欢读长文。
  2. 文章的内容embedding特征,这个召回的时候用过,这里可以选择使用,也可以选择不用,也可以尝试其他类型的embedding特征,比如W2V等。
  3. 用户的设备特征信息

上面这些直接可以用的特征,待做完特征工程之后,直接就可以根据article_id或者是user_id把这些特征加入进去。但是我们需要先基于召回的结果,构造一些特征,然后制作标签,形成一个监督学习的数据集。

构造监督数据集的思路:根据召回结果,我们会得到一个{user_id:[可能点击的文章列表]}形式的字典。那么我们就可以对于每个用户,每篇可能点击的文章构造一个监督测试集,比如对于用户user1假设得到他的召回列表{user1:[item1,item2,item3]},就可以得到三行数据(user1,item1),(user1,item2),(user1,item3)的形式,这就是监督测试集的前两列特征。

构造特征的思路:由于每个用户的点击文章是与其历史点击的文章信息是由很大关联的,比如同一个主题,相似等等。所以特征构造这块很重要的一系列特征是要结合用户的历史点击文章信息。我们已经得到了每个用户及点击候选文章的两列的一个数据集,而我们的目的是要预测最后一次点击的文章,比较自然的一个思路就是和其最后几次点击的文章产生关系,这样既考虑了其历史点击文章信息,又需要离最后一次点击较近,因为新闻很大的一个特点就是注重时效性。**往往用户的最后一次点击会和其最后几次点击有很大的关联。**所以我们就可以对于每个候选文章,做出与最后几次点击相关的特征如下:

  1. 候选item与最后几次点击文章的相似性特征*(embedding内积)* – 这个直接关联用户历史行为
  2. 候选item与最后几次点击文章的相似性特征的统计特征 – 统计特征可以减少一些波动和异常
  3. 候选item与最后几次点击文章的字数差的特征 – 可以通过字数看用户偏好
  4. 候选item与最后几次点击的文章建立的时间差特征 – 时间差特征可以看出该用户对于文章的实时性的偏好。

还需要考虑一下:
5. 如果使用youtube召回的话,我们还可以制作用户与候选item的相似特征
当然,上面只提供了一种基于用户历史行为做特征工程的思路,也可以尝试一些其他特征。

  1. 我们首先获得用户的最后一次点击操作和用户的历史点击,这个基于我们的日志数据集做。
  2. 基于用户的历史行为制作特征,这个会用到用户的历史点击表、最后的召回列表、文章的信息表和embedding向量。
  3. 制作标签,形成最后的监督学习数据集。

导包

import numpy as np
import pandas as pd
import pickle
from tqdm import tqdm
import logging
import time
import lightgbm as lgb
from gensim.models import Word2Vec
from sklearn.preprocessing import MinMaxScaler
import warnings
warnings.filterwarnings('ignore')

数据读取

训练和验证集的划分

划分训练和验证集的原因是为了在线下验证模型参数的好坏,为了完全模拟测试集,我们这里就在训练集中抽取部分用户的所有信息来作为验证集。提前做训练验证集划分的好处就是可以分解制作排序特征时的压力,一次性做整个数据集的排序特征可能时间会比较长。

# all_click_df 指的是训练集
# sample_user_nums 采样作为验证集的用户数量
def trn_val_split(all_click_df,sample_user_nums):      #从训练集中采样
    all_click = all_click_df
    all_user_ids = all_click.user_id.unique()
    
    # replace=True表示可以重复抽样,反之不可以
    sample_user_ids = np.random.choice(all_user_ids,size=sample_user_nums,replace=False)
    
    click_val = all_click[all_click['user_id'].isin(sample_user_ids)]
    click_trn = all_click[~all_click['user_id'].isin(sample_user_ids)]
    
    # 将验证集中的最后一次点击给抽取出来作为答案
    click_val = click_val.sort_values(['user_id','click_timestamp'])
    val_ans = click_val.groupby('user_id').tail(1)
    
    click_val =click_val.groupby('user_id').apply(lambda x:x[:-1]).reset_index(drop=True)
    
    # 去除val_ans中某些用户只有一个点击数据的情况,如果该用户只有一个点击数据,又被分到ans中,
    # 那么训练集中就没有这个用户的点击数据,出现用户冷启动问题,给自己模型验证带来麻烦。
    val_ans = val_ans[val_ans.user_id.isin(click_val.user_id.unique())]  #保证答案中出现的用户
    #在验证集中还有
    click_val = click_val[click_val.user_id.isin(val_ans.user_id.unique())]
    
    return click_trn,click_val,val_ans 

获取历史点击和最后一次点击

# 获取当前数据的历史点击和最后一次点击
def get_hist_and_last_click(all_click):
    all_click = all_click.sort_values(by=['user_id','click_timestamp'])
    click_last_df = all_click.groupby('user_id').tail(1)
    # 如果用户只有一个点击,hist为空了,会导致训练的时候这个用户不可见,此时默认泄露一下
    def hist_func(user_df):
        if len(user_df) == 1 :
            return user_df
        else:
            return user_df[:-1]
    click_hist_df = all_click.groupby('user_id').apply(hist_func).reset_index(drop=True)
    return click_hiat_df, click_last_df

读取训练、验证及测试集

def get_trn_val_tst_data(offline=True):
    if offline:
        click_trn_data = pd.read_csv('train_click_log.csv')  #训练集用户日志
        click_trn_data = reduce_men(click_trn_data)
        click_trn, click_val,val_ans = trn_val_split(all_click_df,sample_user_nums)
    else:
        click_trn = pd.read_csv('train_click_log.csv')
        click_trn = reduce_mem(click_trn)
        click_val = None
        val_ans = None
        
    click_tst = pd.read_csv('testA_click_log.csv')
    
    return click_trn,click_val,click_tst,val_ans

读取召回列表

# 返回多路召回列表或者单路召回
def get_recall_list(single_recall_model=None,multi_recall=False):
    if multi_recall:
        return pickle.load(open('final_recall_items_dict.pkl','rb'))
    
    if single_recall_model == 'i2i_itemcf':
        return pickle.load(open('final_recall_items_dict.pkl','rb'))
    elif single_recall_model == 'i2i_emb_itemcf':
        return pickle.load(open('final_recall_emb_dict.pkl','rb'))
    elif single_recall_model == 'user_cf':
        return pickle.load(open('youtubednn_usercf_dict.pkl','rb'))
    elif single_recall_model == 'youtubednn':
        return pickle.load(open('youtube_u2i_dict.pkl','rb'))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值