协同过滤算法是按照用户的相似度或者物品的相似度来进行推荐的。而LFM模型则是按照用户喜欢的分类来进行推荐。
但是这样就有一个问题,如何去进行分类,分类的颗粒度如何规定。这样的话,我们引进了LFM模型。
LEM不直接计算分类,而是计算每个物品在各个类别中的比重,从而进行计算。
在此,我们使用tensorflow进行模型的构建。
ratings = pd.read_csv("C:/Users/jkx/Desktop/一些数据集/ml-latest-small/ratings.csv")
movies = pd.read_csv("C:/Users/jkx/Desktop/一些数据集/ml-latest-small/movies.csv")
movies['movies_row'] = movies.index
ratings = pd.merge(ratings, movies, how='left', on='movieId')
ratings = ratings[['userId', 'rating', 'movies_row']]
#因为每个人的评分标准不一样,比如A认为最好的电影应该给4分,B认为给5分,所以进行归一化
aggs = ratings.groupby('userId')['rating'].agg(['max'])
ratings = pd.merge(ratings, aggs, on='userId',how='left')
ratings['rating'] = ratings['rating']/ratings['max']
这是处理之后的数据
大部分max是5分,不过还是有不是5分的
num_user = ratings['userId'].max()+1
num_movie = ratings['movies_row'].max()+1
rating = np.zeros((num_movie,num_user))
#标志位
flag = 0
#获取合并表中的列数
ratings_length = np.shape(ratings)[0]
#遍历矩阵,将电影的评分填入表中
for index,row in ratings.iterrows():
rating[int(row['movies_row']), int(row['userId'])] = row['rating']
flag += 1
print('processed %d, %d left' %(flag,ratings_length-flag))
损失函数是:
Theta_parameters矩阵是一个[num_users, num_features]的矩阵,表示了每个用户所喜欢的分类所占的比重。
X_parameters矩阵是一个[num_movies,num_features]的矩阵,表示了每个电影所占分类的比重。
record = rating > 0
record = np.array(record, dtype = int)
rating_norm = rating
num_features = 10
X_parameters = tf.Variable(tf.random_normal([num_movie, num_features],stddev = 0.35))
Theta_parameters = tf.Variable(tf.random_normal([num_user, num_features],stddev = 0.35))
loss = 1/2 * tf.reduce_sum(((tf.matmul(X_parameters, Theta_parameters, transpose_b=True) - rating_norm) * record) ** 2) + 1/2 * (tf.reduce_sum(X_parameters ** 2) + tf.reduce_sum(Theta_parameters ** 2))
optimizer = tf.train.AdamOptimizer(1e-4)
train = optimizer.minimize(loss)
tf.summary.scalar('loss', loss)
summaryMerged = tf.summary.merge_all()
#merge_all 可以将所有summary全部保存到磁盘,以便tensorboard显示。
filename = './movie_tensorborad'
writer = tf.summary.FileWriter(filename)
#指定一个文件用来保存图。
sess = tf.Session()
#定义一个session
init = tf.global_variables_initializer()
sess.run(init)
#运行session
for i in range(50000):
_loss, _, movie_summary = sess.run([loss, train, summaryMerged])
if i%500==0:
print("step {} begins, loss is {}.".format(i,_loss))
writer.add_summary(movie_summary, i)
Current_X_parameters, Current_Theta_parameters = sess.run([X_parameters, Theta_parameters])
# Current_X_parameters为用户内容矩阵,Current_Theta_parameters用户喜好矩阵
predicts = np.dot(Current_X_parameters,Current_Theta_parameters.T)
errors = np.sqrt(np.sum((predicts - rating)**2))
userId = input('您要向哪位用户进行推荐呢?请输入用户编号:(smaller than 672)')
sortedResult = predicts[:, int(userId)].argsort()[::-1]
idx = 0
print('为该用户推荐的评分最高的20部电影是:'.center(80,'='))
for i in sortedResult:
print('score: %.3f, movie name: %s' % (predicts[i, int(userId)], movies.iloc[i]['title']))
idx += 1
if idx == 20:break