基于ItemCF算法的电影推荐系统 的代码详解
作者:互联网
"""
import random
import math
import os
import json
import time
#声明一个ItemCFRec类
class ItemCFRec:
def __init__(self,datafile,ratio):#这是初始的封装类,其他函数都被封装在里面
# 1、原始数据路径文件
self.datafile = datafile
# 测试集与训练集的比例
self.ratio = ratio
self.data = self.loadData()
self.trainData,self.testData = self.splitData(3,47)
self.items_sim = self.ItemSimilarityBest()
# 2、定义函数loadData,新建一个data[],打开并遍历self.datafile每一行,取出userid、itemid、record对应的数据到data[]
def loadData(self):
print("加载数据...")
data=[]
for line in open(self.datafile): #对评分数据的每一行,用::拆分得到三个变量并储存到data中
userid,itemid,record,time1 = line.split("::")
#timestamp = int(1000000000)+int(time1)
timestamp = int(time1)
time_local = time.localtime(timestamp)
dt = time.strftime("%Y-%m-%d %H:%M:%S", time_local)
data.append((userid,itemid,int(record),dt))
#data =data.sort_values(by = 'timestamp')
data1 = sorted(data , key= lambda x: x[3] , reverse = False)
data2 = sorted(data, key=lambda x: x[3], reverse= True)
return data1
"""
拆分数据集为训练集和测试集
k: 参数
seed: 生成随机数的种子
M: 随机数上限
"""
# 3、定义splitData函数,用来随机划分训练集和测试集,
def splitData(self,k,seed,M=9):
print("训练数据集与测试数据集切分...")
train,test = {},{}
random.seed(seed)
for user,item,record in self.data:
if random.randint(0,M) == k:#生成0到m-1之间的随机数
test.setdefault(user,{})#如果字典中包含有给定键,则返回该键user对应的值,否则返回为该键设置的值{}
test[user][item] = record
else:
train.setdefault(user,{})
train[user][item] = record
return train,test
#训练集和测试集的划分 https://blog.csdn.net/qingsi11/article/details/107322751
# 计算物品之间的相似度
#4、创建itemSim、item_user_count、count三个空子典
def ItemSimilarityBest(self):
print("开始计算物品之间的相似度")
# 如果相似度的文件已输出 则直接输出,否则运行else
if os.path.exists("item_sim.json"):
print("物品相似度从文件加载 ...")
itemSim = json.load(open("data/item_sim.json", "r"))
else:
itemSim = dict() # 相似度矩阵(得到每个物品和其他被用户公共喜欢过的物品的相似度值)
item_user_count = dict() # 得到每个物品有多少用户产生过行为(每个物品有行为的用户数)
count = dict() # 共现矩阵(表示同时喜欢两个物品的用户数)
for user, item in self.trainData.items(): #遍历训练集字典中的每一项
#print("user is {}".format(user)) #输出此次遍历的用户
for i in item.keys(): #遍历该用户对应的物品
item_user_count.setdefault(i, 0) #每遍历一次,item_user_count字典增加(物品,行为用户数)
if self.trainData[user][i] > 0.0: #如果该次遍历的用户对该次遍历的物品有评分
item_user_count[i] += 1 #该物品的行为用户数+1
for j in item.keys(): #遍历该用户对应的物品
count.setdefault(i, {}).setdefault(j, 0) #设置count的默认格式(i物品,{j物品,共现次数})
#if self.trainData[str(user)][i] > 0.0 and self.trainData[str(user)][j] > 0.0 and i != j:
if self.trainData[user][i] > 0.0 and self.trainData[user][j] > 0.0 and i != j:
count[i][j] += 1 #若该用户对两不同物品都有评分,这两物品的共现次数+1
#此循环得到物品行为用户数item_user_count和两两物品共现矩阵count
# 共现矩阵 -> 相似度矩阵
for i, related_items in count.items(): #遍历共现矩阵的每一项(i物品,关联物品)
itemSim.setdefault(i, dict()) #设置itemSim的默认格式(i物品,{})
for j, cuv in related_items.items(): #遍历i物品的每一项关联物品(j物品,共现次数)
itemSim[i].setdefault(j, 0) #设置itemSim第i物品的默认格式(j物品,相似度值)
itemSim[i][j] = cuv / math.sqrt(item_user_count[i] * item_user_count[j]) #i,j物品的相似度计算
json.dump(itemSim, open('data/item_sim.json', 'w'))
return itemSim
#计算物品的相似度矩阵 https://blog.csdn.net/cxy861046317/article/details/116115930
"""
为用户进行推荐
user: 用户
k: k个临近物品
nitem: 总共返回n个物品
"""
#生成该用户可能最感兴趣的40个电影的兴趣值的字典
def recommend(self, user, k=8, nitems=40):
result = dict()
u_items = self.trainData.get(user, {})#得到传入参数的该用户的喜爱的物品和对应的评分
#a_items = self.trainData[user]#这种写法也可
for i, pi in u_items.items(): #遍历该用户下的每一项(即每一个物品i及其评分pi)
for j, wj in sorted(self.items_sim[i].items(), key=lambda x: x[1], reverse=True)[0:k]:#对该用户下的i商品在相似度矩阵中和与其他物品的相似度的值排序,reverse=True为倒序
#按照列表中第二个元素(即i物品与j物品的相似度值)对j物品的相似度值wj排序,取与i物品最相似的前k个物品
if j in u_items:
continue #如果物品已经在该用户所选物品中,则跳过,遍历下一个物品
result.setdefault(j, 0) #设置格式(j物品,兴趣值)
result[j] += pi * wj #用该用户对i物品的评分乘以i与j物品的相似度得到该用户对j物品的兴趣值
return dict(sorted(result.items(), key=lambda x: x[1], reverse=True)[0:nitems])
#按照result中每一项的第二个元素(即兴趣值)递减排序,显示前nitems个result
# 计算准确率
def precision(self, k=8,nitems=10):
print("开始计算准确率 ...")
hit = 0
precision = 0
for user in self.testData.keys():#遍历测试集中的user
u_items = self.testData.get(user, {})#得到每一个user看过的电影的评分
result = self.recommend(user, k=k, nitems=nitems)#调用recommen函数,通过训练集预测用户感兴趣的电影,得到result字典
for item, rate in result.items():
if item in u_items:#如果预测的电影在测试集中的该用户看过的电影下,则hit+1
hit += 1
precision += nitems
return hit / (precision * 1.0)#预测的电影在测试集中的该用户看过的电影 的数目/recommend函数预测的推荐的电影数
if __name__ == "__main__":
ib = ItemCFRec("data/ml-1m/ratings.dat",[1,9])#给ItemCFRec("data/ml-1m/ratings.dat",[1,9])取名ib,1:9为测试集与训练集的比例
print("用户1进行推荐的结果如下:{}".format(ib.recommend("1")))#在类ib下给recommend函数传入参数1,得到用户1进行推荐的结果如下:{}
print("准确率为: {}".format(ib.precision()))#在类ib下调用precision函数,得到准确率
参照:https://zhuanlan.zhihu.com/p/94024379
标签:count,items,self,item,算法,详解,ItemCF,user,物品 来源: https://blog.csdn.net/weixin_44133963/article/details/119041849