You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
6.0 KiB

from tqdm import tqdm
import os
import sys
sys.path.append(os.getcwd())
import warnings
import pickle
from config import logger
from config import subject_item_embedding_recall_dict
from config import subject_itemcf_recall_dict
from config import subject_dssm_recall_dict
from config import subject_dssm_usercf_recall_dict
from config import subject_fm_recall_dict
from config import subject_mind_recall0_dict
from config import subject_mind_recall1_dict
from config import subject_pinsage_recall_dict
from config import subject_youtubednn_recall_dict
from config import subject_youtubednn_usercf_recall_dict
from config import subject_final_recall_items_dict
tqdm.pandas()
warnings.filterwarnings('ignore')
def combine_recall_results(user_multi_recall_dict, weight_dict=None, topk=100, save_results=True):
"""
多路召回合并,将所有的召回策略得到的物品列表合并起来
"""
final_recall_items_dict = {}
# 对每一种召回结果按照用户进行归一化,方便后面多种召回结果,相同用户的物品之间权重相加
def norm_user_recall_items_sim(sorted_item_list):
if len(sorted_item_list) < 2:
return sorted_item_list
min_sim = sorted_item_list[-1][1]
max_sim = sorted_item_list[0][1]
norm_sorted_item_list = []
for item, score in sorted_item_list:
if max_sim > 0:
norm_score = 1.0 * (score - min_sim) / (max_sim - min_sim) if max_sim > min_sim else 1.0
else:
norm_score = 0.0
norm_sorted_item_list.append((item, norm_score))
return norm_sorted_item_list
logger.info('开始多路召回合并...')
for method, user_recall_items in tqdm(user_multi_recall_dict.items()):
# 在计算最终召回结果的时候,也可以为每一种召回结果设置一个权重
if weight_dict == None:
recall_method_weight = 1
else:
recall_method_weight = weight_dict[method]
for user_id, sorted_item_list in user_recall_items.items():
# 进行归一化
user_recall_items[user_id] = norm_user_recall_items_sim(sorted_item_list)
for user_id, sorted_item_list in user_recall_items.items():
final_recall_items_dict.setdefault(user_id, {})
for item, score in sorted_item_list:
final_recall_items_dict[user_id].setdefault(item, 0)
final_recall_items_dict[user_id][item] += recall_method_weight * score
final_recall_items_dict_rank = {}
# 多路召回时可以控制最终的召回数量
for user, recall_item_dict in final_recall_items_dict.items():
final_recall_items_dict_rank[user] = sorted(recall_item_dict.items(),
key = lambda x: x[1], reverse = True)[:topk]
if save_results:
logger.info('保存多路召回合并的结果')
pickle.dump(final_recall_items_dict_rank, open(subject_final_recall_items_dict, 'wb'))
return final_recall_items_dict_rank
if __name__ == '__main__':
# 定义多路召回的字典,将多路召回的结果都保存在这个字典当中
user_multi_recall_dict = {'itemcf_recall': {},
'item_embedding_recall': {},
'dssm_recall':{},
'dssm_usercf_recall':{},
'fm_recall':{},
'mind_recall0':{},
'mind_recall1':{},
'pinsage_recall':{},
'youtubednn_recall': {},
'youtubednn_usercf_recall': {}
}
logger.info('加载itemcf召回结果')
user_multi_recall_dict['itemcf_recall'] = pickle.load(open(subject_itemcf_recall_dict, 'rb'))
logger.info('加载item embedding召回结果')
user_multi_recall_dict['item_embedding_recall'] = pickle.load(open(subject_item_embedding_recall_dict, 'rb'))
logger.info('加载dssm召回结果')
user_multi_recall_dict['dssm_recall'] = pickle.load(open(subject_dssm_recall_dict, 'rb'))
logger.info('加载dssm usercf召回结果')
user_multi_recall_dict['dssm_usercf_recall'] = pickle.load(open(subject_dssm_usercf_recall_dict, 'rb'))
logger.info('加载fm召回结果')
user_multi_recall_dict['fm_recall'] = pickle.load(open(subject_fm_recall_dict, 'rb'))
logger.info('加载mind 用户兴趣1召回结果')
user_multi_recall_dict['mind_recall0'] = pickle.load(open(subject_mind_recall0_dict, 'rb'))
logger.info('加载mind 用户兴趣1召回结果')
user_multi_recall_dict['mind_recall1'] = pickle.load(open(subject_mind_recall1_dict, 'rb'))
logger.info('加载pinsage召回结果')
user_multi_recall_dict['youtubednn_usercf_recall'] = pickle.load(open(subject_pinsage_recall_dict, 'rb'))
logger.info('加载YoutubeDNN召回结果')
user_multi_recall_dict['youtubednn_recall'] = pickle.load(open(subject_youtubednn_recall_dict, 'rb'))
logger.info('加载youtube usercf召回结果')
user_multi_recall_dict['youtubednn_usercf_recall'] = pickle.load(open(subject_youtubednn_usercf_recall_dict, 'rb'))
# 每路召回的权重给不同的值,根据前面召回的情况调整参数的值
weight_dict = {'itemcf_recall': 0.7,
'item_embedding_recall': 1.5,
'dssm_recall':2.8,
'dssm_usercf_recall':3.9,
'fm_recall':2.1,
'mind_recall0':1.9,
'mind_recall1':1.9,
'pinsage_recall':8,
'youtubednn_recall': 2.6,
'youtubednn_usercf_recall': 3.9
}
# 最终合并之后每个用户召回300个物品进行排序
final_recall_items_dict_rank = combine_recall_results(user_multi_recall_dict, weight_dict, topk=300)