Task03 多路召回

qinyang_H發表於2020-11-30

所謂的“多路召回”策略,就是指採用不同的策略、特徵或簡單模型,分別召回一部分候選集,然後把候選集混合在一起供後續排序模型使用,可以明顯的看出,“多路召回策略”是在計算速度和召回率之間進行權衡的結果。其中,各種簡單策略保證候選集的快速召回,從不同角度設計的策略保證召回率接近理想的狀態,不至於損傷排序效果。

導包

import pandas as pd
import numpy as np
from tqdm import tqdm
from collections import defaultdict
import os, math, warnings,math,pickle
import faiss
import random
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import LabelEncoder
from datetime import datetime
from deepctr.feature_column import SparseFeat,VarLenSparseFeat
from sklearn.preprocessing import LabelEncoder
from tensorflow.python.keras import backend as K
from tensorflow.python.keras.models import Model
from tensorflow.python.keras.preprocessing.sequence import pad_sequences

from deepmatch.model import *
from deepmatch.utils import sampledsoftmaxloss
warnings.filterwarnings('ignore')

# 做召回評估的一個標誌,如果不進行評估就是直接用全量資料進行召回
metric_recall = False

讀取資料

在一般推薦系統比賽中讀取資料部分主要分為三種模式,不同的模式對應的不同的資料集:

  1. Debug模式:這個的目的幫助我們基於資料先搭建一個簡易的baseline並跑通,保證寫的baseline程式碼沒有什麼問題。由於推薦比賽的資料往往非常巨大,如果一上來就直接採用全部的資料進行分析,搭建baseline框架,往往會帶來時間和裝置上的損耗,所以這時候我們往往需要從海量資料的訓練集中隨機抽取一部分樣本來進行除錯(train_click_log_sample),先跑通一個baseline。
  2. 線下驗證模式:這個目的是幫助我們線上下基於已有的訓練集資料,來選擇好合適的模型和一些超引數,所以我們這一塊只需要載入整個訓練集(train_click_log),然後把整個訓練集再分成訓練集和驗證集,訓練集是模型的訓練資料,驗證集部分幫助我們調整模型的引數和其他的一些超引數。
  3. 線上模式:我們用debug模式搭建起一個推薦系統比賽的baseline,用線下驗證模式選擇好了模型和一些超引數,這一部分就是真正的對於給定的測試集進行預測,提交到線上,所以這一塊使用的訓練資料集是全量的資料集(train_click_log+test_click_log)

下面就分別對這三種不同的資料讀取模式先建立不同的代匯入函式,方便後面針對不同的模式下匯入資料。

# debug模式:從訓練集中劃出一部分資料來除錯程式碼
def get_all_click_sample(data_path,sample_nums=10000):
    """
        訓練集中取樣一部分資料測試
        data_path: 原資料的儲存路徑
        sample_nums: 取樣數目(由於機器記憶體限制,可以取樣使用者做)
    """
    all_click = pd.read_csv('train_click_log.csv')
    all_user_ids = all_click.user_id.unique()
    
    sample_user_ids = np.random.choice(all_user_ids,size=sample_nums,replace=False)
    all_click = all_click[all_click['user_id'].isin(sample_user_ids)]
    
    all_click = all_click.drop_duplicates((['user_id','click_article_id','click_timestamp']))
    return all_click

# 讀取點選資料,這裡分成線上和線下,
#如果是為了獲取線上提交結果應該將測試集中的點選資料合併到總的的資料中
#如果是為了線下驗證模型的有效性或者特徵的有效性,可以只使用訓練集
def get_all_click_df(offline=True):
    if offline:
        all_click = pd.read_csv('train_click_log.csv')
    else:
        trn_click = pd.read_csv('train_click_log.csv')
        tst_click = pd.read_csv('testA_click_log.csv')
        
        all_click = trn_click.append(tst_click)
        
    all_ click = all_click.drop_duplicates((['user_id','click_article_id','click_timestamp']))
    return all_click

# 讀取文章的基本屬性
def get_item_info_df():
    item_info_df = pd.read_csv('articles.csv')
    
    # 為了方便與訓練集中的click_article_id拼接,需要把article_id修改成click_article_id
    item_info_df = item_info_df.rename(columns={'article_id':'click_article_id'})
    
    return item_info_df

# 讀取文章的Embedding資料
def get_item_emb_dict():
    item_emb_df = pd.read_csv('articles_emb.csv')
    
    item_emb_cols = [x for x in item_emb_df.columns if 'emb' in x]
    item_emb_np = np.ascountiguousarray(item_emb_df[item_emb_cols])
    
    #進行歸一化
    item_emb_np = item_emb_np / np.linalg.norm(item_emb_np,axis=1,keepdims=True)
    
    item_emb_dict = dict(zip(item_emb_df['article_id'],item_emb_np))
    pickle.dump(item_emb_dict,open('item_content_emb.pkl','wb'))
    
    return item_emb_dict


max_min_scaler = lambda x : (x-np.min(x))/(np.max(x)-np.min(x))

# 取樣資料
# all_click_df = get_all_click_sample()

# 全量資料集
all_click_df = get_all_clickdf(offline=False)

# 對時間戳進行歸一化,用於在關聯規則的時候計算權重
all_click_df['click_timestamp'] = all_click_df[['click_timestamp']].apply(max_min_scaler)

item_info_df = get_item_info_df()
item_emb_dict = get_item_dict()

工具函式

獲取使用者-文章-時間函式

這個在基於關聯規則的使用者協同過濾的時候會用到

# 根據點選時間獲取使用者的點選文章序列
def get_user_item_time(click_df):
    
    click_df = click_df.sort_values('click_timestamp')
    
    def make_item_pair(df):
        return list(zip(df['click_article_id'],df['click_timestamp']))
    
    user_time_time_df = click_df.groupby('user_id')['click_article_id','click_timestamp'].apply(lambda x:make_item_time_pair(x)).reset_index().rename(columns={0:'item_time_list'})
    user_item_time_dict = dict(zip(user_item_time_df['user_id'],user_item_time_df['item_time_list']))
    return user_item_time_dict

獲取文章-使用者-時間函式

這個在基於關聯規則的文章協同過濾的時候會用到

# 根據時間獲取商品被點選的使用者序列
# 這裡的時間是使用者點選當前商品的時間,好像沒有直接的關係。
def get_item_user_time_dict(click_df):
    def make_user_time_pair(df):
        return list(zip(df['user_id'],df['click_timestamp']))
    
    click_df = click_df.sort_values('click_timestamp')
    item_user_time_df = click_df.groupby('click_article_id')['user_id','click_timestamp'].apply(lambda x:make_user_time_pair(x)).reset_index().rename(columns={0:'user_time_list'})
    
    item_user_time_dict = dict(zip(item_user_time_df['click_article_id'],item_user_time_df['user_time_list']))
    return item_user_time_dict

相關文章