电影推荐系统

这门课感觉挺有意思,而且老师讲的也很好,便决定为代码添上注释自己做一下总结。
代码地址
课程地址
第一步:数据准备
打开网址
电影数据集
找到下图所示数据集进行下载解压。
在这里插入图片描述
第二步:数据准备
读取ratings.csv和movies.csv文件,观察一下两个数据集的内容。
会用到的函数:
tail():查看后几行的数据,默认5行
head():查看前几行的数据,默认5行

ratings数据集:
在这里插入图片描述
movies数据集:
在这里插入图片描述
对数据进行一些处理

#增加行号信息
movies_df['movieRow'] = movies_df.index
# movies_df.tail()

##筛选movies_df中的特征
movies_df = movies_df[['movieRow', 'movieId', 'title']]
movies_df.to_csv('movieProcessed.csv', index=False, header=True, encoding='utf-8')
# movies_df.tail()

#moviesId远大于行号,将ratings_df中的movieId替换为行号
ratings_df = pd.merge(ratings_df, movies_df, on='movieId')
#使用head查看前几行数据,默认前5行
# ratings_df.head()

ratings_df = ratings_df[['userId', 'movieRow', 'rating']]
#处理后的数据保存到文件中
ratings_df.to_csv('ratingsProcessed.csv', index=False, header=True, encoding='utf-8')
# ratings_df.head()

接着创建电影评分矩阵rating和评分记录矩阵record,即用户是否对电影进行了评分,评分则1,未评分则为0。

userNo = ratings_df['userId'].max() + 1
movieNo = ratings_df['movieRow'].max() + 1

rating = np.zeros((movieNo, userNo))

flag = 0
ratings_df_length = np.shape(ratings_df)[0]  #ratings_df的样本个数

利用pycharm中的脚本,可以观察到用户样本数,电影样本数,rating矩阵,ratings_df样本个数.
在这里插入图片描述
填写rating

#填写rating
for index, row in ratings_df.iterrows():
    #将rating当中对应的电影编号及用户编号填上row当中的评分
    rating[int(row['movieRow']), int(row['userId'])] = row['rating']
    flag += 1
    print('processed %d, %d left' % (flag, ratings_df_length - flag))

在电影评分表中,>0表示电影被用户评分,等于0表示未被用户评分。
将布尔值的矩阵转换为0 1表示,即可生成record矩阵。如下三图:

#电影评分表中,>0表示已经评分,=0表示未被评分
record = rating > 0
#bool值转换为0和1
record = np.array(record, dtype=int)

布尔值的record矩阵转变为0 1的record矩阵
在这里插入图片描述
有了这两个矩阵,便可以开始构建模型。
第三步:构建模型
先定义一个对评分取值范围进行缩放的函数,这样能使评分系统性能好一些。

def normalizeRatings(rating, record):
    m, n = rating.shape
    rating_mean = np.zeros((m, 1))  #初始化对于每部电影每个用户的平均评分
    rating_norm = np.zeros((m, n))  #保存处理后的数据
    #原始评分-平均评分,最后将计算结果和平均评分返回。
    for i in range(m):
        idx = record[i, :] != 0  #获取已经评分的电影的下标
        rating_mean[i] = np.mean(rating[i,  idx])  #计算平均值,右边式子代表第i行已经评分的电影的平均值
        rating_norm[i, idx] = rating[i, idx] - rating_mean[i]
    return rating_norm, rating_mean
    
rating_norm, rating_mean = normalizeRatings(rating, record)

rating_norm = np.nan_to_num(rating_norm)
rating_mean = np.nan_to_num(rating_mean)

注1:慕课网课程中的rating_norm[i, idx] 的计算代码有问题,感谢在评论下解惑的大牛们( ̄▽ ̄)~*
注2:如果不对rating_norm,rating_mean进行处理,会报RuntimeWarning: Mean of empty slice.

初始化电影矩阵、用户喜好矩阵,便可以开始计算损失,代价函数即为理论课定义的函数,如图。
注:初始化矩阵产生的参数都是随机数,且服从正态分布:random_normal()
在这里插入图片描述
代码如下:

#假设有10中类型的电影
num_features = 10
#初始化电影矩阵X,用户喜好矩阵Theta,这里产生的参数都是随机数,并且是正态分布
X_parameters = tf.Variable(tf.random_normal([movieNo, num_features], stddev=0.35))
Theta_paramters = tf.Variable(tf.random_normal([userNo, num_features], stddev=0.35))
#理论课定义的代价函数
#tf.matmul(X_parameters, Theta_paramters, transpose_b=True)代表X_parameters和Theta_paramters的转置相乘
loss = 1/2 * tf.reduce_sum(((tf.matmul(X_parameters, Theta_paramters, transpose_b=True)
                             - rating_norm) * record) ** 2) \
       + 1/2 * (tf.reduce_sum(X_parameters**2)+tf.reduce_sum(Theta_paramters**2))  #正则化项,这里λ=1,可以调整来观察模型性能变化。

#创建优化器和优化目标
optimizer = tf.train.AdamOptimizer(1e-4)
train = optimizer.minimize(loss)

第四步:训练模型
使用TensorFlow中的tf.summary模块,它用于将TensorFlow的数据导出,从而变得可视化,因为loss是标量,所以使用scalar函数。
代码如下:

#Step4:训练模型
#使用TensorFlow中的tf.summary模块,它用于将TensorFlow的数据导出,从而变得可视化,因为loss是标量,所以使用scalar函数
tf.summary.scalar('loss', loss)
#将所有summary信息汇总
summaryMerged = tf.summary.merge_all()
#定义保存信息的路径
filename = 'F:\datasets\慕课电影推荐系统数据集\ml-latest-small\movie_tensorboard'
#把信息保存在文件当中
writer = tf.summary.FileWriter(filename)

#创建tensorflow绘画
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)

接下来便开始训练模型,设置10000次迭代,训练过程时间有点长,如果只是想看一下结果,设几十次就好了,但是误差就会比较大。

#开始训练模型
for i in range(10000):
    #不重要的变量可用下划线表示,每次train的结果都会保存到"_",summaryMerged的训练结果保存到"movie_summary"
    _, movie_summary = sess.run([train, summaryMerged])
    writer.add_summary(movie_summary, i)
    #记录一下次数,有没有都无所谓,只是看看还有多久
    print('i=', i, 'loss=', loss)

之前提到可视化,所以接着就是利用可视化观察运行的结果。
进入cmd命令,进入文件位置后,输入"tensorboard --logdir=./ --host=127.0.0.1"
运行后,在浏览器输入127.0.0.1:6006,即可打开可视化TensorFlow的页面观察代价函数

在这里插入图片描述
详细步骤可以看这篇
《TensorBoard返回的网址打不开的问题》

第五步:评估模型

Current_X_paramters, Current_Theta_parameters = sess.run([X_parameters, Theta_paramters])
#将电影内容矩阵和用户喜好矩阵相乘,再加上每一行的均值,便得到一个完整的电影评分表
predicts = np.dot(Current_X_paramters, Current_Theta_parameters.T) + rating_mean
#计算预测值与真实值的残差平方和的算术平方根,将它作为误差error,随着迭代次数增加而减少
errors = np.sqrt(np.sum((predicts - rating)**2))

这是为了赶时间看一下结果,所设置训练50次生成的结果,不出所料,误差很大,但是暂时先忽略⑧
在这里插入图片描述
最后一步:构建完整系统
获取对该用户的电影评分的列表,predicts[:, int(user_id)]是该用户对应的所有电影的评分,即系统预测的用户对于电影的评分。
推荐系统需要从高分开始,所以采用argsort()[::-1]从大到小排序

sortedResult = predicts[:, int(user_id)].argsort()[::-1]

idx用于保存已经推荐了多少部电影

idx = 0
#后边的center函数只是为了美观一点点,不重要
print('为该用户推荐的评分最高的20部电影是:'.center(80, '='))
for i in sortedResult:
    print('评分: %.2f, 电影名: %s' % (predicts[i, int(user_id)], movies_df.iloc[i]['title']))
    idx += 1
    if idx == 20:
        break

以下就是运行后的结果:
在这里插入图片描述
可以看到,为用户推荐的电影已经从高评分到低排列并显示了出来。
一个电影推荐系统便完成了。

注:

#假设有10中类型的电影
num_features = 10
1/2 * (tf.reduce_sum(X_parameters**2)+tf.reduce_sum(Theta_paramters**2))  
#正则化项,这里λ=1,可以调整来观察模型性能变化。
#开始训练模型
for i in range(1000):

这些都是影响系统性能的重要因素,可以修改这些参数来调整系统性能。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐