推荐系统实践(八)----评分预测

2023-11-16

  目前为止都是在讨论 T o p N TopN TopN 推荐,即给定一个用户,如何给他生成一个长度为 N N N 的推荐列表,使该推荐列表能够尽量满足用户的兴趣和需求。本书之所以如此重视 T o p N TopN TopN 推荐,是因为它非常接近于满足实际系统的需求,实际系统绝大多数情况下就是给用户提供一个包括N个物品的个性化推荐列表。
  但是,很多从事推荐系统研究的童鞋最早接触的却是评分预测问题,评分预测问题一直是推荐系统研究的核心。评分预测问题最基本的数据集就是用户评分数据集。该数据集由用户评分记录组成,每一条评分记录是一个三元组 ( u , i , r ) (u,i, r) (u,i,r),表示用户 u u u 给物品 i i i 赋予了评分 r r r,本章用 r u i r_{ui} rui 表示用户 u u u 对物品i的评分。因为用户不可能对所有物品都评分,因此评分预测问题就是如何通过已知的用户历史评分记录预测未知的用户评分记录。

  1. 平均预测算法

  最简单的评分预测算法,就是使用平均值的方法,下面会讲讲各种平均值的使用:

  • 全局平均值
    在平均值里最简单的是全局平均值。它的定义为训练集中所有评分记录的评分平均值:
    μ  =  ∑ ( u , i ) ∈ T r a i n r u i ∑ ( u , i ) ∈ T r a i n 1 \mu {\text{ = }}\frac{{\sum\nolimits_{(u,i) \in Train} {{r_{ui}}} }}{{\sum\nolimits_{(u,i) \in Train} 1 }} μ = (u,i)Train1(u,i)Trainrui
  • 用户评分平均值
    用户 u u u 的评分平均值 r u ‾ \overline {{r_u}} ru 定义为用户 u u u 在训练集中所有评分的平均值:
    r u ‾ = ∑ i ∈ N ( u ) r u i ∑ i ∈ N ( u ) 1 \overline {{r_u}} = \frac{{\sum\nolimits_{i \in N(u)} {{r_{ui}}} }}{{\sum\nolimits_{i \in N(u)} 1 }} ru=iN(u)1iN(u)rui
  • 物品评分平均值
    物品 i i i 的评分平均值 r i ‾ \overline {{r_i}} ri 定义为物品 i i i 在训练集中所有评分的平均值:
    r i ‾ = ∑ u ∈ N ( i ) r u i ∑ u ∈ N ( i ) 1 \overline {{r_i}} = \frac{{\sum\nolimits_{u \in N(i)} {{r_{ui}}} }}{{\sum\nolimits_{u \in N(i)} 1 }} ri=uN(i)1uN(i)rui
  • 用户分类对物品分类的平均值
    假设有两个分类函数,一个是用户分类函数 ϕ \phi ϕ,一个是物品分类函数 φ \varphi φ ϕ ( u ) \phi(u) ϕ(u) 定义了用户 u u u 所属的类, φ ( i ) \varphi(i) φ(i) 定义了物品 i i i 所属的类。那么,我们可以利用训练集中同类用户对同类物品评分的平均值预测用户对物品的评分,即:
    r u i ^ = ∑ ( v , j ) ∈ T r a i n , ϕ ( u ) = ϕ ( v ) , φ ( i ) = φ ( j ) r v j ∑ ( v , j ) ∈ T r a i n , ϕ ( u ) = ϕ ( v ) , φ ( i ) = φ ( j ) 1 \widehat {{r_{ui}}} = \frac{{\sum\nolimits_{(v,j) \in Train,\phi (u) = \phi (v),\varphi (i) = \varphi (j)} {{r_{vj}}} }}{{\sum\nolimits_{(v,j) \in Train,\phi (u) = \phi (v),\varphi (i) = \varphi (j)} 1 }} rui =(v,j)Train,ϕ(u)=ϕ(v),φ(i)=φ(j)1(v,j)Train,ϕ(u)=ϕ(v),φ(i)=φ(j)rvj

前面提出的全局平均值,用户评分平均值和物品评分平均值都是类类平均值的一种特例。

  • 如果定义 ϕ ( u ) = 0 \phi(u)=0 ϕ(u)=0, φ ( i ) = 0 \varphi(i)=0 φ(i)=0,那么 r u i ^ \widehat {{r_{ui}}} rui 就是全局平均值。
  • 如果定义 ϕ ( u ) = μ \phi(u)=\mu ϕ(u)=μ, φ ( i ) = 0 \varphi(i)=0 φ(i)=0,那么 r u i ^ \widehat {{r_{ui}}} rui 就是用户评分平均值。
  • 如果定义 ϕ ( u ) = 0 \phi(u)=0 ϕ(u)=0, φ ( i ) = i \varphi(i)=i φ(i)=i,那么 r u i ^ \widehat {{r_{ui}}} rui 就是物品评分平均值。
    除了这3种特殊的平均值,在用户评分数据上还可以定义很多不同的分类函数。
  • 用户和物品的平均分 对于一个用户,可以计算他的评分平均分。然后将所有用户按照评分平均分从小到大排序,并将用户按照平均分平均分成N类。物品也可以用同样的方式分类。
  • 用户活跃度和物品流行度 对于一个用户,将他评分的物品数量定义为他的活跃度。得到用户活跃度之后,可以将用户通过活跃度从小到大排序,然后平均分为N类。物品的流行度定义为给物品评分的用户数目,物品也可以按照流行度均匀分成N类。
      
  1. 基于邻域算法

  这里主要讲一下基于邻域的方法,其他方法我这里暂时就不考虑了。
  基于用户的邻域算法和基于物品的邻域算法都可以应用到评分预测中。基于用户的邻域算法认为预测一个用户对一个物品的评分,需要参考和这个用户兴趣相似的用户对该物品的评分,即:
r u i ^ = r u ‾ + ∑ v ∈ S ( u , K ) ∩ N ( i ) w u v ( r v i − r v ‾ ) ∑ v ∈ S ( u , K ) ∩ N ( i ) ∣ w u v ∣ \widehat {{r_{ui}}} = \overline {{r_u}} + \frac{{\sum\nolimits_{v \in S(u,K) \cap N(i)} {{w_{uv}}({r_{vi}} - \overline {{r_v}} )} }}{{\sum\nolimits_{v \in S(u,K) \cap N(i)} {|{w_{uv}}|} }} rui =ru+vS(u,K)N(i)wuvvS(u,K)N(i)wuv(rvirv)
  这里, S ( u , K ) S(u, K) S(u,K) 是和用户 u u u 兴趣最相似的 K K K 个用户的集合, N ( i ) N(i) N(i) 是对物品 i i i评过分的用户集合, r v i r_{vi} rvi 是用户 v v v 对物品 i i i 的评分, r v r_{v} rv 是用户 v v v 对他评过分的所有物品评分的平均值。用户之间的相似度 w u v w_{uv} wuv可以通过皮尔逊系数计算, I I I 为用户 u , v u,v uv 同时评价过的物品:
w u v = ∑ i ∈ I ( r u i − r u ‾ ) ( r v i − r v ‾ ) ∑ i ∈ I ( r u i − r u ‾ ) 2 ∑ i ∈ I ( r v i − r v ‾ ) 2 {{\text{w}}_{uv}} = \frac{{\sum\nolimits_{i \in I} {({r_{ui}} - \overline {{r_u}} )({r_{vi}} - \overline {{r_v}} )} }}{{\sqrt {\sum\nolimits_{i \in I} {{{({r_{ui}} - \overline {{r_u}} )}^2}} \sum\nolimits_{i \in I} {{{({r_{vi}} - \overline {{r_v}} )}^2}} } }} wuv=iI(ruiru)2iI(rvirv)2 iI(ruiru)(rvirv)
  
3. 基于邻域算法的实例分析

虎口脱险 变形金刚 唐山大兄 少林足球 大话西游 黑客帝国
A 1 5 4 5
B 4 2 3 5
C 4 3 5
D 5 5 2
E 5 4 4
  • 数据处理
    在这里用户没有对电影评过分的我们将其评分默认为0来处理
	def load_data(filePath):
	    f = open(filePath, "r", encoding="utf-8")
	    records = dict()
	
	    for line in f:
	        user, movie, score = line.strip().split("\t")
	        records.setdefault(user, {})
	        records[user][movie] = int(score)
	
	    return records
	{'A': {'虎口脱险': 1, '变形金刚': 0, '唐山大兄': 5, '少林足球': 4, '大话西游': 5, '黑客帝国': 0}, 'B': {'虎口脱险': 4, '变形金刚': 2, '唐山大兄': 0, '少林足球': 3, '大话西游': 0, '黑客帝国': 5}, 'C': {'虎口脱险': 0, '变形金刚': 4, '唐山大兄': 0, '少林足球': 3, '大话西游': 0, '黑客帝国': 5}, 'D': {'虎口脱险': 5, '变形金刚': 0, '唐山大兄': 5, '少林足球': 0, '大话西游': 2, '黑客帝国': 0}, 'E': {'虎口脱险': 0, '变形金刚': 5, '唐山大兄': 0, '少林足球': 0, '大话西游': 4, '黑客帝国': 4}}
  • 平均值计算
	def item_users_aver(records):
	    item_users = dict()
	    ave_vote = dict()
	    
	    for u, items in records.items():
	        num = 0; sum_score = 0
	        for i, score in items.items():
	            item_users.setdefault(i, {})
	            item_users[i].setdefault(u, 0)
	            item_users[i][u] = score
	            
	            if score != 0:
	                num += 1
	                sum_score += score
	                
	        ave_vote.setdefault(u, 0)
	        ave_vote[u] = sum_score / num
	        
	        print("用户平均评分: ", ave_vote)
   			print("电影-用户倒排列表: ", item_users)
	  
	    return item_users, ave_vote
	用户平均评分:  {'A': 3.75, 'B': 3.5, 'C': 4.0, 'D': 4.0, 'E': 4.333333333333333}
	电影-用户倒排列表:  {'虎口脱险': {'A': 1, 'B': 4, 'C': 0, 'D': 5, 'E': 0}, '变形金刚': {'A': 0, 'B': 2, 'C': 4, 'D': 0, 'E': 5}, '唐山大兄': {'A': 5, 'B': 0, 'C': 0, 'D': 5, 'E': 0}, '少林足球': {'A': 4, 'B': 3, 'C': 3, 'D': 0, 'E': 0}, '大话西游': {'A': 5, 'B': 0, 'C': 0, 'D': 2, 'E': 4}, '黑客帝国': {'A': 0, 'B': 5, 'C': 5, 'D': 0, 'E': 4}}
  • 用户相似度

  这里我觉得《推荐系统实践》中的代码没有考虑到用户没有评分的情况,所以我修改了一下,有不同意见的童鞋可以提出来,大家相互讨论一下。

	def UserSimilarity(records, item_users, ave_vote):
	    nu = dict()
	    W = dict()
	    for i, items in item_users.items():
	        for u, rui in items.items(): 
	            if rui == 0:  # 用户没有评分,直接跳过
	                continue 
	            for v, rvi in items.items():  
	                if u == v or rvi == 0:  # 用户没有评分或者相同用户,直接跳过
	                    continue   # u,v 必须同时对 i 产生评分
	                    
	                nu.setdefault(u, {})
	                nu[u].setdefault(v, 0)
	                nu[u][v] += pow((rui - ave_vote[u]), 2)
	            
	                W.setdefault(u, {})
	                W[u].setdefault(v, 0)
	                W[u][v] += (rui - ave_vote[u])*(rvi - ave_vote[v])
	                
	    for u in W:
	        W[u] = {v: y/sqrt(nu[u][v]*nu[v][u]) for v, y in W[u].items()}
	    
	    print("用户相似度: ", W)
	    
	    return W
	用户相似度:  {'A': {'B': -0.7682212795973759, 'D': -0.49951243284357016, 'C': -1.0, 'E': -1.0}, 'B': {'A': -0.7682212795973759, 'D': 1.0, 'C': 0.6488856845230502, 'E': -0.9486832980505137}, 'D': {'A': -0.49951243284357016, 'B': 1.0, 'E': 1.0}, 'C': {'B': 0.6488856845230502, 'E': -0.4472135954999575, 'A': -1.0}, 'E': {'B': -0.9486832980505137, 'C': -0.4472135954999575, 'A': -1.0, 'D': 1.0}}
  • 预测
    我们这里使用用户 A A A 对电影《唐山大兄》进行预测:
	def PredictAll(records, test, ave_vote, W, K):
	    user_items = dict()
	
	    user, movie, score = test.strip().split(" ")
	    predict = int(score)
	    norm = 0
	    for v, wuv in sorted(W[user].items(), key=itemgetter(1), reverse=True)[0:K]:  # 和user相似度最高的K个用户
	        if movie in records[v]:
	            rvi = records[v][movie]
	            predict += wuv * (rvi - ave_vote[v])
	            norm += abs(wuv)
	    if norm > 0:
	        predict /= norm
	    predict += ave_vote[user]
	    
	    print("《", movie, "》预测分数: ", predict)
	    
	    return predict
	《 唐山大兄 》预测分数:  5.476910016088435

  
4. 总结

  其实实际生活中使用推荐会考虑多种方法,不管是基于邻域还是矩阵分解等等,具体使用看具体情况决定,只要能最高效,获得最好结果就行。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

推荐系统实践(八)----评分预测 的相关文章

随机推荐

  • AD铺铜中铺地选择异形铺铜方式

    在使用AD时 最后的一步铺铜 铺地 如果是矩形的板子 铺铜很简单 直接捕捉拐角点即可 但是一些异形的板子 就不是那么好办了 虽然可以全选铺铜 最后也不影响最后的PCBA实物 但是有强迫症的肯定会看着不舒服 比如我 所以找到一种快速铺异形板子
  • Go(一)变量和常量

    目录 标识符与关键字 标识符 关键字 变量 变量的来历 变量类型 变量声明 标准声明 批量声明 变量的初始化 类型推导 短变量声明 匿名变量 常量 iota 几个常见的iota示例 标识符与关键字 标识符 在编程语言中标识符就是程序员定义的
  • Spark数据处理实战之列空值&新增列处理

    在spark dataset dataframe操作过程中 我们经常会遇到对于一个列值的一些判断情况 是否为NULL 创建一个新列等 本文讲解了常用的增加列的方法 并且对于列空值判断 填充处理以及查询的api做了详细的描述和实例讲解 阅读完
  • 思科交换机密码破解

    年纪大了 总是忘记cisco交换机密码 现将我初始化cisco交换机密码的两大步13个小步骤记录如下 A 1 打开电脑中SecureCRT软件 或者下载windows7 超级终端 v1 01 绿色版 hypertrm exe 把port C
  • 人人都看得懂的正则表达式教程

    编写验证规则最流行和最简单的方法就是正则表达式了 但唯一的一个问题是正则表达式的语法太隐晦了 让人蛋疼无比 很多开发者为了在项目中应用复杂的验证 经常要使用一些小抄来记住正则式的复杂语法和各种常用命令 在这篇文章中 我将试图让大家明白什么是
  • uboot 设置环境变量

    1 使用命令 ipconfig 查看 windows 系统的 IP 2 使用命令 ifconfig 查看虚拟机 ubuntu 系统的 IP 3 串口登录 fs4412 的uboot 4 在uboot中输入命令 print 打印当前环境变量
  • 如何将栈中的元素输出

    首先需要写一个出栈函数 得到栈顶的值 才能将其输出 bool Pop SqStack s ElemType e if s gt top 1 return false e s gt data s gt top s gt top return
  • android启动优化

    主题 我们今天讨论的主题是 使用第三方工具 CPU Profile 来优化app的启动时间 背景 想要进行app的启动优化有一点必须要知道的就是Android的启动流程和启动状态 启动流程 Android的启动流程相关的知识点 各位可以去查
  • MySQL索引1

    索引最大作用就是提高对表中数据的查询速度 就像书的目录那样重要 可以快速查到所需的知识 上面是11万多条数据的表 使用语句查询 如 耗时 0 108s 再比如 用时 0 004s 接下来创建索引 在t book上右键 选择管理索引 选择新建
  • 基于vue 2.X和高德地图的vue-amap组件获取经纬度

    今天我就讲了一下怎么通过vue和高德地图开发的vue amap组件来获取经纬度 这是vue amap的官网文档 https elemefe github io vue amap 这是我的码云项目的地址 http git oschina ne
  • MySQL函数和存储过程

    MySQL流程控制函数 1 IF函数 IF expr1 expr2 expr3 如果expr1是真 返回expr2 否则返回expr3 SELECT name IF age gt 18 成年 未成年 FROM user 2 IFNULL函数
  • 给Qt程序添加管理员权限总结(一定有你没见过的方式)

    当我们写了一个Qt程序 程序会在C盘某些目录下创建文件时 会发现代码没有问题 但是就是创建失败 而当我们对程序右键 以管理员权限运行时 又可以正常创建文件 此时 说明我们的程序默认不具备管理员权限 故而无法对某些目录进行写入 根据我们的编译
  • 温酒读Qt:QObject 序篇

    一 醉言醉语话夏娃 跟Qt框架打了这么久交道 Qt貌似对我的半斤八两知根知底 我对Qt的认知却还不到半斤八两 o o 或许你知道Qt的meta object和属性系统 或许你在写代码时无数次显示或者隐示的继承了QObject 不管人家是否乐
  • 数据库数据恢复-SQL SERVER数据库分区被格式化的数据恢复方案

    SQL SERVER数据库故障类型 1 SQL SERVER数据库文件被删除 2 SQL SERVER数据库所在分区格式化 3 SQL SERVER数据库文件大小变为 0 4 使用备份还原数据库时覆盖原数据库 SQL SERVER数据库故障
  • Sublime Text 中Anaconda 插件的Python语法配置

    在Ubuntu环境下Sublime Text 配置Anaconda 插件自动检查Python3语法 在Ubuntu16 04环境下使用Sublime Text 写Python3程序 已安装了Anaconda 插件包 通过配置Anaconda
  • Fabric java sdk 1.4简明教程

    在超级账本Fabric区块链中 应用通过节点的RPC协议接口访问链码 Java应用可以使用官方提供的Fabric sdk java开发包来实现对链码的访问 开发包封装了Fabric区块链的GRPC链码访问协议 有利于开发人员聚焦于业务逻辑
  • TCP报文的交互过程

    TCP建立连接和断开连接的过程如下图所示 在TCP 协议提供可靠的连接服务时 采用三次握手建立一个连接 采用四次握手来关闭一个连接 建立TCP连接的三次握手 第一次握手 建立连接时 客户端发送 SYN 包到服务器 等待服务器确认 第二次握手
  • Docker的简介、镜像及优化

    1 docker的安装 1 配置yum源 vim etc yum repo d docker ce repo 编辑内容 vim etc yum repo d CentOS Base repo 编辑内容 2 安装docker yum inst
  • 医疗保健行业中的区块链

    区块链技术是世界上最重要和最具颠覆性的技术之一 多个行业正在采用区块链技术来创新其运作方式 希望采用区块链的行业之一是医疗保健行业 在本指南中 我们将熟悉区块链 特别是有助于打破这个行业原有桎梏的功能 此外 我们将研究医疗行业的未来将会是什
  • 推荐系统实践(八)----评分预测

    目前为止都是在讨论 T o p N TopN TopN 推荐 即给定一个用户 如何给他生成一个长度为 N N