python基于物品协同过滤算法实现代码
程序员文章站
2023-01-05 14:18:53
本次测试基于movielens数据集实现的基于物品的协同过滤,目前只是在小样本上实现,主要问题是计算太耗内存,后期代码继续优化与完善。
数据集说明:movies.d...
本次测试基于movielens数据集实现的基于物品的协同过滤,目前只是在小样本上实现,主要问题是计算太耗内存,后期代码继续优化与完善。
数据集说明:movies.dat中数据是用户对电影的评分。数据格式:userid::movieid::rating::timestamp。
代码
import pandas as pd import numpy as np import math import os import time import datetime os.chdir(r'f:\zxx\pthon_work\cf') def loaddata(): #读入movies.dat, rating.dat,tags.dat #mnames=['movie_id','title','genres'] #movies=pd.read_table(r'.\data\movies.dat',sep='::',header=none,names=mnames) rnames=['userid','movieid','rating','timestamp'] all_ratings=pd.read_table(r'.\data\ratings.dat',sep='::',header=none,names=rnames,nrows=300000) #tnames=['userid','movieid','tag','timestamp'] #tags=pd.read_table(r'.\data\tags.dat',sep='::',header=none,names=tnames) return all_ratings #数据探索:rating def data_alay(ratings): """rating nums10000054, 3, 示例 : 1 122 5 838985046 col:'userid','movieid','rating','timestamp' """ #一个用户只对一个电影打分一次 ur=ratings.groupby([ratings['userid'],ratings['movieid']]) len(ur.size) #计算每部电影的平均打分,电影数10677 def avgrating(ratings): movies_mean=ratings['rating'].groupby(ratings['movieid']).mean()#计算所有用户对电影x的平均打分 movies_id=movies_mean.index movies_avg_rating=movies_mean.values return movies_id,movies_avg_rating,movies_mean #计算电影相似度矩阵相,即建立10677*10677矩阵 def calculatepc(ratings): movies_id,movies_avg_rating,movies_mean=avgrating(ratings) #pc_mat=np.eye(3)#建立电影相似度单位矩阵 pc_dic={} top_movie=len(movies_id) for i in range(0,top_movie): for j in range(i+1,top_movie): movieaid=movies_id[i] moviebid=movies_id[j] see_moviesa_user=ratings['userid'][ratings['movieid']==movieaid] see_moviesb_user=ratings['userid'][ratings['movieid']==moviebid] join_user=np.intersect1d(see_moviesa_user.values,see_moviesb_user.values)#同时给电影a、b评分的用户 moviea_avg=movies_mean[movieaid] movieb_avg=movies_mean[moviebid] key1=str(movieaid)+':'+str(moviebid) key2=str(moviebid)+':'+str(movieaid) value=twomoviespc(join_user,movieaid,moviebid,moviea_avg,movieb_avg,ratings) pc_dic[key1]=value pc_dic[key2]=value #pc_mat[i][i+1]=twomoviespc(join_user,movieaid,moviebid,moviea_avg,movieb_avg,ratings) #print ('---the %s, %d,%d:--movie %s--%s--pc is %f' % (key1,movieaid,moviebid,movieaid,moviebid,pc_dic[key1])) return pc_dic #计算电影a与电影b的相似度,皮尔森相似度=sum(a-a^)*sum(b-b^)/sqrt(sum[(a-a^)*(a-a^)]*sum[(b-b^)*(b-b^)]) def twomoviespc(join_user,movieaid,moviebid,moviea_avg,movieb_avg,ratings): cent_ab_sum=0.0#相似度分子 centa_sum=0.0#分母 centb_sum=0.0#分母 movieab_pc=0.0#电影a,b的相似度 count=0 for u in range(len(join_user)): #print '---------',u count=count+1 rata=ratings['rating'][ratings['userid']==join_user[u]][ratings['movieid']==movieaid].values[0]#用户给电影a评分 ratb=ratings['rating'][ratings['userid']==join_user[u]][ratings['movieid']==moviebid].values[0]#用户给电影b评分 cent_ab=(rata-moviea_avg)*(ratb-movieb_avg) #去均值中心化 centa_square=(rata-moviea_avg)*(rata-moviea_avg) #去均值平方 centb_square=(ratb-movieb_avg)*(ratb-movieb_avg)#去均值平方 cent_ab_sum=cent_ab_sum+cent_ab centa_sum=centa_sum+centa_square centb_sum=centb_sum+centb_square if(centa_sum>0 and centb_sum>0 ): movieab_pc=cent_ab_sum/math.sqrt(centa_sum*centb_sum) return movieab_pc """ 预测用户u对那些电影感兴趣。分三步, 1)用户u过去x天看过的电影。 2)提出用户u已看过的电影,根据用户u过去看过的电影,计算用户u对其他电影的打分. 3) 拉去打分最高的的电影给用户推荐。 预测用户u对电影c的打分。分三步:(先只做这个) 1)用户u过去x天看过的电影。 2)利用加权去中心化公式预测用户u对电影c的打分. """ #日期处理: -3天,然后转换为uinxtime def timepro(last_rat_time,useru): lastdate= datetime.datetime.fromtimestamp(last_rat_time[useru]) #unix转为日期 date_sub3=lastdate+datetime.timedelta(days=-3)#减去3天 unix_sub3=time.mktime(date_sub3.timetuple())#日期转为unix return unix_sub3 #取用户最后一次评分前3天评估的电影进行预测 def gethisrat(ratings,last_rat_time,useruid): unix_sub3= timepro(last_rat_time,useruid) useru_info=ratings[ratings['userid']==useruid][ratings['timestamp']>unix_sub3] return useru_info #预测用户u对电影c的打分 def hadseenmoviebyuser(useruid,moviea,ratings,pc_dic,movies_mean): pre_rating=0.0 last_rat_time=ratings['timestamp'].groupby([ratings['userid']]).max()#获取用户u最近一次评分日期 useru_info= gethisrat(ratings,last_rat_time,useruid)#获取用户u过去看过的电影 flag=0#表示新电影,用户u是否给电影a打过分 wmv=0.0#相似度*mv平均打分去均值后之和 w=0.0#相似度之和 movie_useru=useru_info['movieid'].values#当前用户看过的电影 if moviea in movie_useru: flag=1 pre_rating=useru_info['rating'][useru_info['movieid']==moviea].values else: for mv in movie_useru: key=str(mv)+':'+str(moviea) rat_u_mv=useru_info['rating'][useru_info['movieid']==mv][useru_info['userid']==useruid].values#用户u对看过电影mv的打分 wmv=(wmv+pc_dic[key]*(rat_u_mv-movies_mean[mv]))#相似度*mv平均打分去均值后之和 w=(w+pc_dic[key])#看过电影与新电影相似度之和 #print ('---have seen mv %d with new mv %d,%f,%f'%(mv,moviea,wmv,w)) pre_rating=(movies_mean[moviea]+wmv/w) print ('-flag:%d---user:%d rating movie:%d with %f score----' %(flag,useruid,moviea,pre_rating)) return pre_rating,flag if __name__=='__main__': all_ratings=loaddata() movie_num=100#控制电影数,只针对电影id在该范围的数据进行计算,否则数据量太大 ratings=all_ratings[all_ratings['movieid']<=movie_num] movies_id,movies_avg_rating,movies_mean=avgrating(ratings) pc_dic=calculatepc(ratings)#电影相似度矩阵 #预测 useruid=10#当前数据集只看过电影4,7, moviea=6 pre_rating,flag=hadseenmoviebyuser(useruid,moviea,ratings,pc_dic,movies_mean) "-----------------测试id提取------------------" #选取useruid ratings.head(10)#从前10行中随机选取一个用户id,例如:userid=10 #查看该用户在当前数据集中看过那些电影,方便选取新电影(防止选择的是用户已经看过的电影) ratings[ratings['userid']==10]#该用户在当前数据集中,只看过电影movieid in(4,7),则可选择不是4,7的电影id进行预测,例如6.
运行结果:
-flag:0---user:10 rating movie:6 with 4.115996 score----
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。