基于改进的协同过滤算法的用户评分预测模型

来源:互联网 发布: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
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 迅雷会员为什么不能加速怎么办 持有st创智股票怎么办 租的房子床坏了怎么办 宜家定时器不响怎么办 新插座插不进去怎么办 本溪人社app打不开怎么办 南宁电车超过上牌时间怎么办 苹果6s降频怎么办 0首付手机还不起怎么办 乐才app登录不上怎么办 买了笔记本网要怎么办? 电脑连接不上网络怎么办 电脑上没网络了怎么办 手机返回键不好使怎么办 笔记本无线网连接受限怎么办 魅族打电话图标没有了怎么办 京东价格保护后发票怎么办 淘宝未满十八岁怎么办 SVN提交时代码冲突怎么办 京东自营没货了怎么办 京东下了单 没货怎么办 万达广场购物卡怎么办 京东白条没额度怎么办 京东退款还收到货怎么办 退货不想要货了怎么办 安装微擎创建数据库失败怎么办 tp文件损坏或丢失怎么办 手机QQ启动有问题应该怎么办 微信网页版页面巨大怎么办 魔兽军团烹饪食谱扔了怎么办 赴港旅游网上签证怎么办了? 美团商家入住没有营业执照怎么办 团购房子不想要怎么办 乐视液晶屏坏了怎么办 wifi盒子插上网线然后怎么办 在泰国手机坏了怎么办 朋友在泰国手机关机怎么办 qq上转账转错了怎么办 扣扣转账转错了怎么办 到付快递签收了怎么办 京东白条消费了怎么办