ItemBasedCF.py
首先这个.py文件是基于多个用户评价的电影数据,利用surprise自带的KNN库去计算整个数据集的相似矩阵。再利用测试用户的评价数据和相似矩阵去选出与测试用户相似度最高的K个电影
下图是此类运用到的几个库:
from MovieLens import MovieLens
from surprise import KNNBasic
from collections import defaultdict
from operator import itemgetter
from time import time
其中,之前没有介绍的有KNNBasic这个surprise库自带的KNN算法,想要了解详情可以点击KNNBasic这里我介绍一下在这里调用时用到的重要参数sim_options,这个参数是相似性度量的选项字典,具体参数如下:
这个文件中用到的是name和user_based参数,因为这里的是根据电影去计算相似性,所以user_based参数选择False。
代码中的数据导入之后,还有一个我们没接触过的surprise内置算法,那就是data调用的build_full_trainset()函数。下面是他的底层源码,我进行了详细注释:
def construct_trainset(self, raw_trainset):
raw2inner_id_users = {} # 用户的内置id字典,键为用户id,值为第几位用户
raw2inner_id_items = {} # 用户的内置item字典, 键为用户id, 值为第几个电影
current_u_index = 0
current_i_index = 0
ur = defaultdict(list)
ir = defaultdict(list)
# 用户原始id, 电影原始id, 电影评分, 时间戳
for urid, irid, r, timestamp in raw_trainset:
try:
uid = raw2inner_id_users[urid] # 内置用户id
# 如果不存在此原始用户的内置id,就把当前的内置id赋值过去,并且内置id加一
except KeyError:
uid = current_u_index
raw2inner_id_users[urid] = current_u_index
current_u_index += 1
try:
iid = raw2inner_id_items[irid]
except KeyError:
iid = current_i_index
raw2inner_id_items[irid] = current_i_index
current_i_index += 1
# 内置用户id和内置电影id互相对应,且把评分加上
ur[uid].append((iid, r))
ir[iid].append((uid, r))
n_users = len(ur) # 用户数量
n_items = len(ir) # 电影数量
n_ratings = len(raw_trainset) # 评分数量
# 构造返回数据集
trainset = Trainset(ur,
ir,
n_users,
n_items,
n_ratings,
self.reader.rating_scale,
raw2inner_id_users,
raw2inner_id_items)
return trainset
下面是此文件的详细代码,有详细注释:
# 创建一个MoviesLens类
ml = MovieLens()
# 调用函数导入数据
data = ml.loadMovieLensDataset()
# 构建使用 KNN 算法计算相似性的完整训练集
trainSet = data.build_full_trainset()
# 定义相似性度量值以估计评级. 在这里,我们使用的cosine相似性。
# 因为我们需要根据电影计算相似性,所以"user_based":False
sim_options = {'name': 'cosine',
'user_based': False}
model = KNNBasic(sim_options=sim_options)
t0 = time()
# 用trainSet训练集去训练
model.fit(trainSet)
# 生成相似性矩阵
similarityMatrix = model.compute_similarities()
testUser = '0'
# 将我们想要的预测的用户的原始 ID 转换为可供surprise库使用的内部 ID
user_inner_id = trainSet.to_inner_uid(testUser)
# 获取用户已评分电影的默认评分列表
check_user_ratings = trainSet.ur[user_inner_id]
# 将K个评分最高的项目放入列表中,其中键为项目 ID,值为评分
k = 40
kNeighbors = sorted(check_user_ratings, key=lambda x: x[1], reverse=True)[:k]
# 获取与用户喜欢的电影类似的电影,按评级加权
similarItems = defaultdict(float)
for itemID, ratings in kNeighbors:
similarityRow = similarityMatrix[itemID]
for innerID, score in enumerate(similarityRow):
similarItems[innerID] += score * (ratings/5.0)
# 构建用户已经看过的电影字典,它们将是用户已经为其评分过的 trainSet 中的电影
watched={}
for itemID, rating in trainSet.ur[user_inner_id]:
watched[itemID] = 1
# 获取评分最高的几个电影并打印出来
count = 0
number = 1
print('Recommended Movies using Item Based Collaborative Filtering:')
for itemID, ratingSum in sorted(similarItems.items(),key=itemgetter(1),reverse=True):
if not itemID in watched:
movieID = trainSet.to_raw_iid(itemID)
print(number,'-',ml.getMovieName(int(movieID)))
number += 1
count += 1
if count >= 15:
break
tt=time()-t0
print("Item based CF Model trained in %s seconds" % round(tt,3))