组队学习:推荐系统Task1:Baseline
第一次阅读这么多代码,感触就是,首先要看懂整体代码的逻辑,否则陷进去又不知道它们在做什么!
Baseline的整体逻辑其实很简单:
1.定义了一个节省内存的函数,但之后没用过了
def reduce_mem(df)
2.定义了一个从训练集从部分采样的函数,用作debug调试,但之后没用过了
def get_all_click_sample(data_path, sample_nums=10000):
3.定义了一个获取点击数据的函数(内部分为线上和线下):
def get_all_click_df(data_path='./data_raw/', offline=True):
并在此处获取全量训练集:
all_click_df = get_all_click_df(offline=False)
之后没用过get_all_click_df()了,说明此函数就是用来得到all_click_df的。
all_click_df在四个地方使用了:
#获取文章相似度
i2i_sim = itemcf_sim(all_click_df)
# 获取 用户 - 文章 - 点击时间的字典
user_item_time_dict = get_user_item_time(all_click_df)
# 用户热度补全
item_topk_click = get_item_topk_click(all_click_df, k=50)
for user in tqdm(all_click_df['user_id'].unique()):
user_recall_items_dict[user] = item_based_recommend(user, user_item_time_dict, i2i_sim, sim_item_topk, recall_item_num, item_topk_click)
4.定义了一个获取“user-item-time”字典的函数:
def get_user_item_time(click_df):
此函数的两次使用都是同一句话:
user_item_time_dict = get_user_item_time(all_click_df)
说明此函数就是为了得到变量user_item_time_dict!
而user_item_time_dict主要是用作函数item_based_recommend()的参数:
def item_based_recommend(user_id, user_item_time_dict, i2i_sim, sim_item_topk, recall_item_num, item_topk_click):
5.定义了一个获取点击量最多的k个文章的函数:
def get_item_topk_click(click_df, k):
之后该函数只使用了一次就是在“给每个用户根据物品的协同过滤推荐文章”代码块中的#用户热度补全处:
item_topk_click = get_item_topk_click(all_click_df, k=50)
6.定义了一个基于itemCF的文章相似度的函数:
def itemcf_sim(df):
并用全量数据集进行了相似度计算:
i2i_sim = itemcf_sim(all_click_df)
此后没再使用该函数了,说明次函数就是用来得到变量i2i_sim的!
使用ctrl+f查找,发现i2i_sim就是用来当做item_based_recommend()的参数来用的!
7.定义了一个基于itemCF的文章推荐的函数:
def item_based_recommend(user_id, user_item_time_dict, i2i_sim, sim_item_topk, recall_item_num, item_topk_click):
之后在“给每个用户根据物品的协同过滤推荐文章”代码块的末尾使用了该函数。
8.定义了一个生成提交文件的函数:submit()。在本节最后使用了。
整体逻辑:
1.定义了2个暂时未用到的函数:reduce_mem()和get_all_click_sample()
2.定义函数get_all_click_df()来获取变量all_click_df
3.定义函数get_user_item_time()来获取变量user_item_time_dict
4.定义函数get_item_topk_click()获取变量item_topk_click,用于最后的热度补全
5.定义函数itemcf_sim()获取变量i2i_sim
6.定义变量sim_item_topk = 10选择与当前文章最相似的前k(k=10)篇文章
7.定义最后的召回文章数量recall_item_num = 10
8.定义一个基于itemCF的文章推荐的函数:(查看参数列表可知,上述所有变量的准备都是现在这一刻!!)
item_based_recommend(user_id, user_item_time_dict, i2i_sim, sim_item_topk, recall_item_num, item_topk_click):
9.item_based_recommend()函数就是为了得到字典user_recall_items_dict!
以下部分就相当于C++中的main函数阶段了,“万事俱备,只欠东风”,所有变量、函数全部定义做好了,开始执行item_based_recommend()函数,获取实实在在的字典user_recall_items_dict!
user_recall_items_dict = collections.defaultdict(dict)
for user in tqdm(all_click_df['user_id'].unique()):
user_recall_items_dict[user] = item_based_recommend(user, user_item_time_dict, i2i_sim,
sim_item_topk, recall_item_num, item_topk_click)
10.将user_recall_items_dict转化为Dataframe格式的变量recall_df:
user_item_score_list = []
for user, items in tqdm(user_recall_items_dict.items()):
for item, score in items:
user_item_score_list.append([user, item, score])
recall_df = pd.DataFrame(user_item_score_list, columns=['user_id', 'click_article_id', 'pred_score'])
11.recall_df作为submit函数的参数提交
def submit(recall_df, topk=5, model_name=None):
12.最终提交:(执行submit函数)
# 获取测试集
tst_click = pd.read_csv(data_path + 'testA_click_log.csv')
tst_users = tst_click['user_id'].unique()
# 从所有的召回数据中将测试集中的用户选出来
tst_recall = recall_df[recall_df['user_id'].isin(tst_users)]
# 生成提交文件
submit(tst_recall, topk=5, model_name='itemcf_baseline')
从抄一遍代码,到代码运行不出错,到最后产生的结果文件不出错,真是千难万难!
debug汇总:
1.81行的’click_article_id’粗心写成’click_ar’
2.把第75-78行的data_path去掉了
3.140行的items()写成了item()
4.17行和18行的 data_path = ‘./data_raw’ save_path = ‘./tmp_results’最后都少了个斜杠!应该是data_path = ‘./data_raw/’ save_path = ‘./tmp_results/’
5.144行’itemcf_i2i_sim.pkl’写成了’item_i2i_sim.pkl’导致FileNotFoundError
6.要在工程内创建一个data_raw文件夹和一个tmp_results文件夹!!
7.108行’click_article_id’写成了’click_df’!!(ctrl+f找到的)
8.108行value_counts()写成了value_counts()!!
9.240行的’.csv’写成了’csv’,虽然没报错,但是生成的文件错了
10.237行直接没抄导致生成的文件内容错误!!submit.columns = [int(col) if isinstance(col, int) else col for col in submit.columns.droplevel(0)]
11.235行的unstack(-1)没抄!s
12.终极错误:138行的i2i_sim_ = i2i_sim.copy()对其了第二个for而不是第一个for,导致最终的提交文件里所有人推荐的文章都一样!
13.终极错误:135行i2i_sim[i].setdefault(j, 0) 136行i2i_sim[i][j] += 1/math.log(len(item_time_list) + 1)不能与continue对齐!!