推荐系统实战 Task01——小白笔记
文章目录
题目要求
根据用户点击的历史文章数据,为用户推荐最大概率会点击的五篇文章文章。
Baseline中的关键就是文章与文章的相似性矩阵的计算。 以下是我在跑通和理解Baseline时接触到的一些新知识。以及理解。Baseline
导入库
import time, math, os
from tqdm import tqdm #显示循环的进度条
import gc #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
warnings.filterwarnings('ignore') #过滤警告器
使用warnings.filterwarnings(‘ignore’) 可以去掉那些招人烦的warning。
collections.defaultdict模块
dict =defaultdict(factory_function) #例如:dict=defaultdict(int)
字典的一般用法是dict={},添加元素只需要dict[element] =value,调用的时候也是如此,dict[element] =
xxx,但如果字典中没有element这个key就会报错。而defaultdict,当字典里的key不存在但被查找时,会根据你的设定给它一个默认值。这个默认值根据你的factory_function参数选择来确定。
factory_function | 默认值 |
---|---|
int | 0 |
str | 空字符串 |
set | set() |
ilist | [] |
节约内存的一个标配函数
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
这是一个通用的节省内存函数,很多地方(比如DataFrame数据)都可以直接调用。
数据预处理
# 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
numpy.random.choice
numpy.random.choice(a, size=None, replace=True, p=None)
参数 | 意义 |
---|---|
a | 必须是一维的,并组成指定大小(size)的数组 |
replace | False表示不可以取相同数字,True表示可以取相同数字,默认为True |
p | 为数组,与数组a相对应,表示取数组a中每个元素的概率,默认为选取每个元素的概率相同 |
读取点击数据,这里分成线上和线下,如果是为了获取线上提交结果应该将测试集中的点击数据合并到总的数据中。
如果是为了线下验证模型的有效性或者特征的有效性,可以只使用训练集。
这里为了线上提交数据,将测试集与训练集数据合并
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
计算物品相似度
def itemcf_sim(df):
user_item_time_dict = get_user_item_time(df)
# 计算物品相似度
i2i_sim = {}
item_cnt = defaultdict(int) #初始化为0
for user, item_time_list in tqdm(user_item_time_dict.items()):
# 在基于商品的协同过滤优化的时候可以考虑时间因素
for i, i_click_time in item_time_list:
item_cnt[i] += 1
i2i_sim.setdefault(i, {})
for j, j_click_time in item_time_list:
if(i == j):
continue
i2i_sim[i].setdefault(j, 0)
i2i_sim[i][j] += 1 / math.log(len(item_time_list) + 1)
i2i_sim_ = i2i_sim.copy()
for i, related_items in i2i_sim.items():
for j, wij in related_items.items():
i2i_sim_[i][j] = wij / math.sqrt(item_cnt[i] * item_cnt[j])
# 将得到的相似性矩阵保存到本地
pickle.dump(i2i_sim_, open(save_path + 'itemcf_i2i_sim.pkl', 'wb'))
return i2i_sim_
此处的权重计算公式我想可以改用余弦相似度、皮尔逊相关系数或者其它更优的。
总结
Baseline提交的结果只有0.0984,我想在计算相似度那一块可以换其它的计算公式,这应该对准确率有所提高。