推荐系统实战(6)——评估

1、打分系统-评分误差率

def RMSE(records):
    return math.sqrt(sum([(rui-pui)*(rui-pui) for u,i,rui,pui in records])/float(len(records)))
def MAE(records):
    return sum([abs(rui-pui) for u,i,rui,pui in records])/float(len(records))

 

关于 RMSE MAE 这两个指标的优缺点, Netflix 认为 RMSE 加大了对预测不准的用户物品评
分的惩罚(平方项的惩罚),因而对系统的评测更加苛刻。研究表明,如果评分系统是基于整数
建立的(即用户给的评分都是整数),那么对预测结果取整会降低 MAE 的误差

2、Top-N推荐系统

 

网站在提供推荐服务时,一般是给用户一个个性化的推荐列表,这种推荐叫做 TopN 推荐。
TopN 推荐的预测准确率一般通过准确率( precision / 召回率( recall )度量。
R ( u ) 是根据用户在训练集上的行为给用户作出的推荐列表,而 T ( u ) 是用户在测试集上的行
为列表。那么,推荐结果的召回率和准确率分别定义为:
 

 

2.1 准确率

协同过滤算法的离线实验一般如下设计。首先,将用户行为数据集按照均匀分布随机分成 M
份(本章取 M =8 ),挑选一份作为测试集,将剩下的 M -1 份作为训练集。然后在训练集上建立用户
兴趣模型,并在测试集上对用户行为进行预测,统计出相应的评测指标。为了保证评测指标并不
是过拟合的结果,需要进行 M 次实验,并且每次都使用不同的测试集。然后将 M 次实验测出的评
测指标的平均值作为最终的评测指标。
下面的 Python 代码描述了将数据集随机分成训练集和测试集的过程:
def splitData(self, M, k, seed=1):
    '''
    :params: data, 加载的所有(user, item)数据条目
    :params: M, 划分的数目,最后需要取M折的平均
    :params: k, 本次是第几次划分,k~[0, M)
    :params: seed, random的种子数,对于不同的k应设置成一样的
    :return: train, test
    '''
    train, test = [], []
    random.seed(seed)
    for user, item in self.data:
        # 这里与书中的不一致,本人认为取M-1较为合理,因randint是左右都覆盖的
        if random.randint(0, M-1) == k:  
            test.append((user, item))
        else:
            train.append((user, item))

    # 处理成字典的形式,user->set(items)
    def convert_dict(data):
        data_dict = {}
        for user, item in data:
            if user not in data_dict:
                data_dict[user] = set()
            data_dict[user].add(item)
        data_dict = {k: list(data_dict[k]) for k in data_dict}
        return data_dict

    return convert_dict(train), convert_dict(test), self.profile
这里,每次实验选取不同的 k 0 k M 1 )和相同的随机数种子 seed ,进行 M 次实验就可
以得到 M 个不同的训练集和测试集,然后分别进行实验,用 M 次实验的平均值作为最后的评测指
标。这样做主要是防止某次实验的结果是过拟合的结果( over fitting ),但如果数据集够大,模型
够简单,为了快速通过离线实验初步地选择算法,也可以只进行一次实验。
 
def Precision(train,test,N):
    hit=0 
    all=0
    for user in train.keys():
        tu = test[user]
        rank=GetRecommendation(user,N)#推荐物品
        for item,pui in rank:
            if item in tu:
                hit+=1
        all+=N
    return hit/(all * 1.0)

2.2 召回率

def Recall(train,test,N):
    hit=0
    all=0
    for user in train.keys():
        tu  = test[user]
        rank = GetRecommendation(user,N)#推荐物品
        for item,pui in rank:
            if item in tu:
                hit +=1
        all += len(tu)
    return hit/(all * 1.0)

2.3、覆盖率

 

def Coverage(train,test,N):
    recommend_items=set()
    all_items =set()
    for user in train,keys():
        for item in train[user].keys():
            all_items.add(item)
        rank=GetRecommendation(user,N)
        for item,pui in rank:
            recommend_items.add(item)
    return len(recommend_items)/(len(all_items)*1.0)

2.4、多样性

 

2.5、其他(新颖度、惊喜度、信任度、实时性)

最后,我们还需要评测推荐的新颖度,这里用推荐列表中物品的平均流行度度量推荐结果的
新颖度。如果推荐出的物品都很热门,说明推荐的新颖度较低,否则说明推荐结果比较新颖。
def Popularity(train,test,N):
    item_popularity=dict()
    for user,items in train.items():
        for item in items.keys():
            if item not in item_popularity:
                item_popularity[item]=0
            item_popularity[item]+=1
    ret = 0
    n=0
    for user in train.keys():
        rank = GetRecommendation(user,N)
        for item,pui in rank:
            ret += math.log(1+item_popularity[item])
            n+=1
    ret /=n*1.0
    return ret

 

这里,在计算平均流行度时对每个物品的流行度取对数,这是因为物品的流行度分布满足长
尾分布,在取对数后,流行度的平均值更加稳定。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值