这门课感觉挺有意思,而且老师讲的也很好,便决定为代码添上注释自己做一下总结。
第一步:数据准备
打开网址https://grouplens.org/datasets/movielens/,找到下图所示数据集进行下载解压。
第二步:数据准备
读取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的页面观察代价函数
详细步骤可以看这篇https://blog.csdn.net/qq_30377909/article/details/89946818
第五步:评估模型
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):
这些都是影响系统性能的重要因素,可以修改这些参数来调整系统性能。
附上代码链接:
https://github.com/jiangnanxiaoshuaigua/movies_recommend_system