推荐模型之PopRec

618 阅读2分钟
参与拿奖:本文已参与「新人创作礼」活动,一起开启掘金创作之路
ps:代码文末自取

1.相关概念

这里的PopRec指的是基于流行度的推荐模型,根据item出现的次数来进行推荐,是基于item展现次数的推荐模型,也是推荐领域最简单的模型。

2.代码

2.1 数据预处理

这里使用的是Amazon[1]数据集为例。需要处理的数据,每一行的内容是user_id item_ids,内容如下图所示:

image.png

现在将倒数第二个item之前的item作为查询集合,最后一个item作为target用于测试。这里不需要考虑测试集中的数据不在训练集中,因为不在训练集中,表明其展现次数为0,可以忽略。

import numpy as np
import pandas as pd
import os

"""根据流行度对用户进行推荐,不需要训练集、验证集,区分真实数据与原始数据"""
def dataProcess(filename,topk):
    """
    :param:
    filename:需要处理的数据文件名
    topk:最好的k个推荐
    :return:
     original_data: 原始数据(去掉最后一个item的数据)
     data_dic:原始数据形成的数据字典
     actual_data:每个user的最后一个item数据
    """
    original_data=[]
    train_data=[]
    data_dic={}
    actual_data=[]
    with open(os.getcwd()+filename) as f:
        d_f=f.readlines()
    for d in d_f:
        temp=list(map(int,d.split(" ")))
        train_data.append(temp[1:-1*topk])
        original_data.extend(temp[1:-1*topk])
        actual_data.append(temp[-topk:])

    for i_ in original_data:
        data_dic[i_]=data_dic.get(i_,0)+1

    return train_data,actual_data,data_dic



if __name__ == '__main__':
    filename="/data/Sports_and_Outdoors.txt"
    train,test,_=dataProcess(filename,1)
    print(train[0],test[0])

image.png

2.2 PopRec

from dataProcessing import *
from utils import *


def PopRec(original_data,actual_data,data_dic,topk):
    data_dic=sorted(list(data_dic.keys()),key=lambda x:data_dic[x],reverse=True)
    pred=[[] for _ in range(len(actual_data))]
    for i in range(len(actual_data)):
        for j in data_dic:
            if len(pred[i])<topk and j not in original_data[i]: # 保证了推荐的item不在user的交互历史中    
                    pred[i].append(j)
    return pred,actual_data

2.3 评价函数


def ndcg_k(actual, predicted, topk):
    res = 0
    for user_id in range(len(actual)):
        k = min(topk, len(actual[user_id]))
        idcg = idcg_k(k)
        dcg_k = sum([int(predicted[user_id][j] in set(actual[user_id])) / math.log(j+2, 2) for j in range(topk)])
        res += dcg_k / idcg
    return res / float(len(actual))


# Calculates the ideal discounted cumulative gain at k
def idcg_k(k):
    res = sum([1.0/math.log(i+2, 2) for i in range(k)])
    if not res:
        return 1.0
    else:
        return res

def recall_at_k(actual, predicted, topk):
    sum_recall = 0.0
    num_users = len(predicted)
    true_users = 0
    for i in range(num_users):
        act_set = set(actual[i])
        pred_set = set(predicted[i][:topk])
        if len(act_set) != 0:
            sum_recall += len(act_set & pred_set) / float(len(act_set))
            true_users += 1
    return sum_recall / true_users

2.4 打印结果

def metric_all(tag):
    filename=os.listdir(os.getcwd()+"/data/")
    with open("result.txt","w+") as ff:
        for f in filename:
            if f[-4:] !=".txt":
                continue
            print(f)
            original_data, actual_data, data_dic=dataProcess("/data/"+f)
            ff.write(f+"\n")
            for t in tag:
                pred, actual= PopRec(original_data, actual_data, data_dic,t)
                rc_t=round(recall_at_k(actual,pred,t),4)
                ndcg_t=round(ndcg_k(actual,pred,t),4)
                print('HIT@{0} : {1} , NDCG@{0} : {2}'.format(t,rc_t,ndcg_t))
                ff.write('HIT@{0} : {1} , NDCG@{0} : {2}'.format(t,rc_t,ndcg_t))
                ff.write("\n")

运行结果

Beauty.txt
HIT@1 : 0.0008 , NDCG@1 : 0.0008
HIT@5 : 0.0077 , NDCG@5 : 0.0042
HIT@10 : 0.0135 , NDCG@10 : 0.0061
HIT@15 : 0.0174 , NDCG@15 : 0.0071
HIT@20 : 0.0217 , NDCG@20 : 0.0081
HIT@25 : 0.0238 , NDCG@25 : 0.0086
HIT@30 : 0.0254 , NDCG@30 : 0.0089

参考资料

[1] Amazon

[2] 代码github自取