推荐系统入门
刚入门推荐系统,接触的第一个项目记录下来学习一下。
项目比赛链接:https://tianchi.aliyun.com/notebook-ai/detail?postId=144449
任务:推荐用户喜欢的文章
User-base和Item-base
User-base:当用户A和BC喜欢的物品相似的时候,将BC的物品推荐给A。缺点:物品数量大重叠性小,用户增加的时候计算量增加。
Item-base:根据用户历史来计算物品之间的相似性,将用户喜欢物品的相似物品推荐给用户。计算方法为:wij=同时喜欢ij物品的用户数量除以根号下喜欢i物品的用户乘以喜欢j物品的用户。
简单粗暴我们直接上代码进行分析。
引包:这里我们要提到defaultdict,可以使用collections类中的defaultdict()方法来为字典提供默认值。然后itemgetter可以用来获得某一维度的值。彼得都是常见的。
# import packages import time, math, os from tqdm import tqdm import gc import pickle import random from datetime import datetime from operator import itemgetter import numpy as np import pandas as pd import warnings from collections import defaultdict import collections warnings.filterwarnings('ignore')
第一个模块:节约内存的优化函数。这里实际是按照每一列能装载数据的最小数据结构进行存储,这样可以优化60%左右的空间。
memory_usage()函数可以获得df使用的内存,字节为单位,除以两个1024就是mb。
# 节约内存的一个标配函数 def reduce_mem(df): starttime = time.time() numerics = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64'] start_mem = df.memory_usage().sum() / 1024**2 for col in df.columns: col_type = df[col].dtypes if col_type in numerics: c_min = df[col].min() c_max = df[col].max() if pd.isnull(c_min) or pd.isnull(c_max): continue if str(col_type)[:3] == 'int': if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max: df[col] = df[col].astype(np.int8) elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max: df[col] = df[col].astype(np.int16) elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max: df[col] = df[col].astype(np.int32) elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max: df[col] = df[col].astype(np.int64) else: if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max: df[col] = df[col].astype(np.float16) elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max: df[col] = df[col].astype(np.float32) else: df[col] = df[col].astype(np.float64) end_mem = df.memory_usage().sum() / 1024**2 print('-- Mem. usage decreased to {:5.2f} Mb ({:.1f}% reduction),time spend:{:2.2f} min'.format(end_mem, 100*(start_mem-end_mem)/start_mem, (time.time()-starttime)/60)) return df
第二个模块,数据集的预处理,我们可能需要从训练集中划分出一些数据出来,使用unique()和random.choice()来随机选择id。这个函数暂时没使用。
下面那个是整合了train和test的数据集,线下就用一个训练集(自己拆分训练验证),线上就把数据全用上进行训练。
# debug模式:从训练集中划出一部分数据来调试代码 def get_all_click_sample(data_path, sample_nums=10000): """ 训练集中采样一部分数据调试 data_path: 原数据的存储路径 sample_nums: 采样数目(这里由于机器的内存限制,可以采样用户做) """ all_click = pd.read_csv(data_path + '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(data_path='./data_raw/', offline=True): if offline: all_click = pd.read_csv(data_path + 'train_click_log.csv') else: trn_click = pd.read_csv(data_path + 'train_click_log.csv') tst_click = pd.read_csv(data_path + '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 # 全量训练集 all_click_df = get_all_click_df(data_path, offline=True)
第三个模块,做出一个点击序列,唯一的用户id对应一个大列表,里面分别是他每次点击的物品和点击的时间。从这个序列中我们可以知道这个用户都点击了什么。通过list(zip(df[A],df[B]))将
['click_article_id', 'click_timestamp']合成一个元组,然后rename成为item time list。返回的user item time dict 就是一个用户 物品 时间的点击表。
get_item_topk_click不必多说,就是把文章按照id做一个value_counts()然后取前k个
# 根据点击时间获取用户的点击文章序列 {user1: [(item1, time1), (item2, time2)..]...} def get_user_item_time(click_df):
click_df = click_df.sort_values('click_timestamp') def make_item_time_pair(df): return list(zip(df['click_article_id'], df['click_timestamp'])) user_item_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_topk_click(click_df, k): topk_click = click_df['click_article_id'].value_counts().index[:k] return topk_click

浙公网安备 33010602011771号