基于改进的协同过滤算法的用户评分预测模型
来源:互联网 发布:windows 多线程 编辑:程序博客网 时间:2024/05/14 00:30
目标:精确预测某目标用户对目标电影M的评分值。
步骤:1得到与目标电影M最相似的K个电影集合ci。
2.基于ci,计算评论过m电影且与目标用户最相似的k2个用户
3.将与目标用户最相似的k2个用户对目标电影M的评分值加权平均值作为目标用户对目标电影评分预测值。
4测试不同k值,不同目标用户对电影M的预测值减目标用户对电影M的实际评分值,结果显示评分误差在0.6左右,说明算法预测精度非常高。
相关公式模型:
1电影相似度计算公式(修正的余弦相似度计算公式)
其中:Uij为同时评论电影ij的所有用户集合,ru,i为用户u对电影i的评分值,/ru为用户u评论的所有电影的评分平均值。
2.用户相似度计算公式
ci为1中计算的与电影i最相似的k个电影集合,u,v代表两个用户,ru,i为用户u对电影i的评分值。可以看到,根据此公式,用户间相似度为0等价于两用户对同一电影评分的值相差1分。
3.评分预测模型
4模型评估方法
实现代码及注释:
#-*- coding: utf-8 -*-import mathclass UserBasedCF: def __init__(self,datafile = None,k1=300,k2=2000):#构造函数初始化 self.readData(datafile=datafile,k1=k1,k2=k2)#载入数据 self.cacheData() def readData(self,datafile=None,k1=300,k2=2000): data = [] for line in open(datafile): userid,itemid,record,_ = line.strip('\n').split("::") if (int(userid)<k1)&(int(itemid)<k2):#设置训练集的大小 data.append((userid,itemid,int(record)))#data列表存储用户id,电影id,得分 self.data=data return data def cacheData(self): self.userItemScore=dict()#{用户:{电影1:评分,电影2:评分2}} self.user_items = dict()#{用户:set(看过的电影集合)} self.item_users = dict()#{电影:set(看过该电影的用户集合)} #仅仅遍历一次数据,形成三个中间结果查询字典 for user,item,rate in self.data: if user not in self.userItemScore: self.userItemScore.setdefault(user,{}) self.userItemScore[user][item]=int(rate) if item not in self.item_users: self.item_users.setdefault(item,set()) self.item_users[item].add(user) if user not in self.user_items: self.user_items.setdefault(user,set()) self.user_items[user].add(item) ''' #寻找hotmovie hotmovie={} for i in self.item_users.keys(): hotmovie.setdefault(i,len(self.item_users[i])) self.hotmovie=sorted(hotmovie.items(),key = lambda x : x[1],reverse = True)[0:20] print self.hotmovie ''' def itemSimBest(self,targetMovie='1210',k=[190,200]):#设置目标电影,与返回的最相似电影个数 self.targetMovie=targetMovie #计算每个targetmovie以外的电影与movie的相似度 simmj=dict()#存电影m与j的相似度 for j in self.item_users.keys():#j为所有电影 if j==targetMovie:continue umj=self.item_users[targetMovie]&self.item_users[j]#同时评论过电影mj的用户集合 if umj==set([]):continue#如果没有用户共同评论电影mj则跳出本次循环 #中间结果计算,计算umj中每个用户给出评分的平均值 umjj=dict()#umjj存对电影mj同时进行过评论的用户的平均分 for u in umj: ucum=0 for i in self.userItemScore[u].items(): ucum+=float(i[1])#所有电影得分相加 umean=ucum/len(self.userItemScore[u])#该用户评分总分/评论的电影数 umjj[u]=umean#用户评分平均分,加入字典 #print(umjj)#与u共同评论了mj电影的用户v有····他们各自的平均评分为 {'75': 3.92, '92': 2.8545454545454545} #对相似度计算的分子 fenzi=fenmu1=fenmu2=0 for v in umj:#i为用户 fenzi+=(self.userItemScore[v][targetMovie]-umjj[v])*(self.userItemScore[v][j]-umjj[v]) fenmu1+=pow(self.userItemScore[v][targetMovie]-umjj[v],2) fenmu2+=pow(self.userItemScore[v][j]-umjj[v],2) if fenmu1*fenmu2==0:simmj[j]=0 else: sim=fenzi/(math.sqrt(fenmu1)*math.sqrt(fenmu2)) simmj[j]=sim #m与j项目相似度为sim #字典排序,取出与m最相似的k个电影 simmj=sorted(simmj.items(),key = lambda x : x[1],reverse = True) if len(simmj)<max(k):print "K值不能大于simmmj集合的元素个数————simmj集合的个数为"+str((len(simmj))) simmjkDict={}#存放不同k值,对应的最相似电影集合 for i in k: simmjkDict[i]=dict(simmj[0:i])#i为k return simmjkDict def userSimBest(self,simmjkDict,simk=0.00001): self.rightSimTargetuuDict={}#存放不同K值下,符合条件的目标用户与其多个相似用户的相似值 for key in simmjkDict.keys():#key就是topk这个列表 simmjk=simmjkDict[key] simmjk=set(simmjk.keys())#准备ci #print 'simmjk' #print len(simmjk) userm=list(self.item_users[self.targetMovie])#获取评论过目标电影的用户集合 rightSimTargetuu={}#有的tagetu的ci为空集,所以需要找到ci不为空集的targetu结果如图 #print 'len user m' #print len(userm) for targetu in userm:#找到符合条件的targetu simtargetuu={}#找到与tagetu最相似的几个用户 for u in userm:#评论过目标电影的集合 if targetu==u:continue ci=self.user_items[targetu]&self.user_items[u]&simmjk if len(ci)>5: cum=0.0 for a in ci: cum+=pow((self.userItemScore[targetu][a]-self.userItemScore[u][a]),2) simtargetuu[u]=1.0-(cum*1.0)/len(ci) if len(simtargetuu)!=0:rightSimTargetuu[targetu]=simtargetuu #print rightSimTargetuu #因为ci设置过小,会使得有的用户相似度计算结果为负或者0这种相似度值当然不适合预测,所以需要去除奇异值 for u in rightSimTargetuu.keys(): for v in rightSimTargetuu[u].keys(): if rightSimTargetuu[u][v]<simk:del rightSimTargetuu[u][v]#设定相似度阈值 for u in rightSimTargetuu.keys():#删除{‘151’:{}}这样的空值 if rightSimTargetuu[u]=={}: del rightSimTargetuu[u] #print 'del sim dic' #print rightSimTargetuu #self.rightSimTargetuu=rightSimTargetuu if len(rightSimTargetuu)==0:print "对k="+str(key)+" 没有匹配的相似用户,需要降低相似度阈值or增加K or 改变目标电影" self.rightSimTargetuuDict[key]=rightSimTargetuu #print self.rightSimTargetuuDict.keys() #print self.rightSimTargetuuDict[200] def predictAndEvaluation(self): m=self.targetMovie K_MAE_Dict={} for key in self.rightSimTargetuuDict.keys(): rightSimTargetuu=self.rightSimTargetuuDict[key] predictTargetScore={} for u in rightSimTargetuu.keys(): fenzi=fenmu=0.0 for v in rightSimTargetuu[u].keys(): fenzi+=rightSimTargetuu[u][v]*self.userItemScore[v][m] fenmu+=rightSimTargetuu[u][v] predictTargetScore[u]=fenzi*1.0/fenmu #test result cum=0.0 for i in predictTargetScore.keys(): cum+=abs(predictTargetScore[i]-self.userItemScore[i][m]) if len(predictTargetScore.keys())==0:break MAE=math.sqrt(cum/len(predictTargetScore.keys())) K_MAE_Dict[key]=MAE K_MAE_Dict=sorted(K_MAE_Dict.items(),key = lambda x : x[0],reverse = False) print "对目标电影 "+str(self.targetMovie)+" 不同k值对应的MAE值" print K_MAE_Dictdef testModel(): cf=UserBasedCF('ratings.dat',k1=300,k2=2000)#载入数据文件。由于原始数据集是由6040个用户对3900个电影评论产生的逾100万条电影评论数据 #原始数据较大,故可以使用k1,k2参数获取原始数据子集进行模型效果初步检验 #k1代表用户id范围,k2代表电影id范围(0<k1<6040,0<k2<3900) print "数据样例:" print cf.data[0:6]#打印部分数据样例 print "载入的数据条目数量"+str(len(cf.data)) k=[190,200,205,210,]#设定与目标电影最相似的k个电影数值。当k<<number(共同评论目标电影m与电影j的人数数量) Top-k个电影 simmjkDict=cf.itemSimBest(targetMovie='260',k=k)#求目标电影的K-Top个最相似电影 #最好选热门电影,可以的热门电影有:1196、1210、260、1198、593、110、1265、589、318、1197、608、296、527、1617、1 cf.userSimBest(simmjkDict,simk=0.00001)#simk为用户相似度的阈值。根据你的相似度计算公式,用户相似度值大于0,即相似度很高,不建议修改该默认阈值 cf.predictAndEvaluation()if __name__ == "__main__": testModel()
实现结果:
合作者:湖南大学 李剑锋
0 0
- 基于改进的协同过滤算法的用户评分预测模型
- 一个memory-based协同过滤算法的改进(基于隐式评分)
- 基于用户的协同过滤推荐模型
- 基于在线评分的协同过滤算法---Slope One算法
- 基于用户的协同过滤算法
- 基于用户的协同过滤算法
- 基于用户的协同过滤算法
- 基于用户的协同过滤推荐算法
- 基于用户的协同过滤算法
- 基于用户的协同过滤推荐算法
- 基于用户的协同过滤算法
- 基于用户的协同过滤算法实验
- 基于用户的协同过滤算法
- Python-基于用户的协同过滤算法
- 基于用户的协同过滤算法详解
- 基于用户的协同过滤
- 基于用户的协同过滤算法vs基于物品的协同过滤算法
- 基于用户的协同过滤算法和基于物品的协同过滤算法之java实现
- iOS 启动页
- Linux--进程间通信(信号量,共享内存)
- android lichee编译脚本解析
- 前端CSS规范整理
- PHP 中dirname(_file_)讲解
- 基于改进的协同过滤算法的用户评分预测模型
- Leetcode Merge k Sorted Lists 合并k个链表
- APP列表之下拉刷新
- Swift之旅(五)枚举与结构体
- tmux使用指南
- JAVA设计模式(14):行为型-中介者模式(Mediator)
- 排序算法——快速排序
- 进程间通信的方法
- 浅谈JAVA设计模式之——模板方法(TemplateMethod)