赞
踩
现在在互联网的时代,你会发现有很多智能的推荐系统,比如说商品的推荐,歌曲的推荐,电影的推荐。在推荐系统中,协同过滤算法是诞生最早的,也是很常用的推荐算法。有句古话:物以类聚,人以群分。推荐算法的思想就是找到和你相似的人,也就是口味相同的人,把他喜欢的物品或者电影歌曲推荐给你;或者是将你买过的或者喜欢的物品,电影或者歌曲推荐给你;还有就是可能将你搜索过的物品、电影或者歌曲推荐给你;还有可能就是综合上述的算法做推荐。
我们来看看协同过滤算法的流程吧:
这个步骤其实就是大数据的收集处理,这些数据其实反映了用户的某些偏好,通过分析用户的行为评分,基于用户所有的数据来做出推荐。
首先我们拿到了用户的数据之后要对数据进行处理,处理的依据主要可以分为:
协同过滤(collaborative filtering)算法主要有两个分支,基于用户的协同过滤(user-based collaborative filtering)和基于商品的协同过滤(item-based collaborative filtering)。如何查找相似的用户和商品,这里就涉及到相似度的计算了,下面是几个计算相似度的方法:
上面我们有说过协同过滤分成两种过滤方法,基于用户的和基于商品的。首先我们来说一下基于用户的协同过滤推荐方法:基于用户的推荐大体意思就是我们来找到一些相似性很高的用户,那么别人喜欢的商品也很有可能是你喜欢的商品,我们以此来作为依据推荐。还有一种就是基于商品的推荐,其实也很容易理解,类似于基于用户的协同过滤,这里就是寻找商品之间的关系,商品之间的相似度,关联度,以此来对用户做推荐,所以我们经常会在网购的时候发现一些推荐,比如购买了此商品的用户还购买了XXX,这就是基于商品协同过滤的推荐。
有了这些数学和理论的基础,我们就可以用TensorFlow来构建一套电影的推荐系统。
首先我们要准备数据集,数据集可以从电影数据集链接 来下载解压得到.csv文件。
首先我们要导入Python的几个库:
import pandas as pd
import numpy as np
import tensorflow as tf
然后是读取电影评分的ratings.csv文件
ratings_df = pd.read_csv('Desktop/ml-latest-small/ratings.csv')
就可以查看这张电影评分表的内容了,我们来看一下这个表中最后几行的内容
ratings_df.tail()
同样,我们来读取电影库的.csv文件
movies_df = pd.read_csv('Desktop/ml-latest-small/movies.csv')
movies_df.tail()
我们来看看电影列表中的最后几行内容:
增加一列名为movieRow的索引值,内容为行号:
movies_df['MovieRow'] = movies_df.index
movies_df.tail()
相较于上一张图,我们可以看到最后多了一列索引值,和行号相等。
我们清洗好了数据之后,就可以将数据进行特征提取,从而拿到我们需要的一些数据。
movies_df = movies_df[['MovieRow','movieId','title']]
movies_df.tail()
我们从电影列表中提取出"movieRow"、"movieId"和"title"三列数据,可以得到:
然后我们将这个列表作为处理好的数据储存起来方便后面用到:
movies_df.to_csv('Desktop/ml-latest-small/moviesProcessed.csv',index = False, header = True, encoding = 'utf-8')
储存好了特征提取之后的数据之后,我们将评分列表和电影列表合并,并对其movieId这一列。
ratings_df = pd.merge(ratings_df, movies_df, on = 'movieId')
ratings_df.head()
合并两张表之后,我们将合并好的表再来提取特征:
ratings_df = ratings_df[['userId','MovieRow','rating']]
ratings_df.head()
特征提取完成之后,首先我们来获取评分的用户和电影的数量:
userNo = ratings_df['userId'].max()+1
movieNo = ratings_df['MovieRow'].max()+1
接下来创建一个movieNo行,userNo列,内容是0的矩阵:
rating = np.zeros((movieNo,userNo))
设置一个标签位flag,然后获取合并之后列表的列数,然后遍历rating矩阵每一个位置,将电影的评分填入矩阵中:
#标志位
flag = 0
#获取合并表中的列数
ratings_df_length = np.shape(ratings_df)[0]
#遍历矩阵,将电影的评分填入表中
for index,row in ratings_df.iterrows():
rating[int(row['MovieRow']), int(row['userId'])] = row['rating']
flag += 1
print('processed %d, %d left' %(flag,ratings_df_length-flag))
然后我们来获取一个电影是否被用户评分的列表,其中1代表该电影已经被用户评分,0是用户没有对该电影评分:
record = rating > 0
record = np.array(record, dtype = int)
record
可以得到结果矩阵:
array([[0, 0, 0, ..., 0, 1, 1],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]])
同时我们也可以得到评分的矩阵:
array([[0., 0., 0., ..., 0., 4., 5.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
...,
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.]])
构建模型之前,我们来定义一个标准化评分表的方法:
def normalizeRatings(rating, record):
#获取电影的数量m和用户的数量n
m,n = rating.shape
#rating_mean-电影平均分 rating_norm-标准化后的电影得分
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])
rating_norm[i,idx] -= rating_mean[i]
return rating_norm, rating_mean
然后我们对我们数据进行标准化的时候,会出现以下的问题:
/usr/local/lib/python3.6/site-packages/numpy/core/fromnumeric.py:2957: RuntimeWarning: Mean of empty slice.
out=out, **kwargs)
/usr/local/lib/python3.6/site-packages/numpy/core/_methods.py:80: RuntimeWarning: invalid value encountered in double_scalars
ret = ret.dtype.type(ret / rcount)
这是因为在处理数据的时候,大量出现nan引起的,所以我们将nan的地方转成数字0:
rating_norm = np.nan_to_num(rating_norm)
可以得到标准化后的矩阵:
array([[ 0. , 0. , 0. , ..., 0. ,
-3.87246964, -3.87246964],
[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ],
[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ],
...,
[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ],
[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ],
[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ]])
同理我们计算电影平均的评分:
rating_mean = np.nan_to_num(rating_mean)
array([[3.87246964],
[3.40186916],
[3.16101695],
...,
[3. ],
[0. ],
[5. ]])
接下来就是用TensorFlow来构建模型:
num_features = 10
X_parameters = tf.Variable(tf.random_normal([movieNo, num_features],stddev = 0.35))
Theta_parameters = tf.Variable(tf.random_normal([userNo, num_features],stddev = 0.35))
我们可以根据基于内容推荐算法的损失函数公式:
J
(
θ
)
=
1
2
∑
j
=
1
u
∑
i
,
r
(
i
,
j
)
=
1
(
(
θ
(
j
)
)
T
x
i
−
y
(
i
,
j
)
)
2
+
λ
2
∑
j
=
1
u
∑
k
=
1
n
(
θ
k
(
j
)
)
2
J(\theta ) = \frac{1}{2}\sum\limits_{j = 1}^u {\sum\limits_{i,r(i,j) = 1} {{{({{({\theta ^{(j)}})}^T}{x^i} - {y^{(i,j)}})}^2} + \frac{\lambda }{2}\sum\limits_{j = 1}^u {\sum\limits_{k = 1}^n {{{(\theta _k^{(j)})}^2}} } } }
J(θ)=21j=1∑ui,r(i,j)=1∑((θ(j))Txi−y(i,j))2+2λj=1∑uk=1∑n(θk(j))2
在这个公式中,r(x,y)是评分记录表,u是用户数量,θ(j)是j用户的喜好,y(i,j)是i用户对j电影的评分,xi表示电影的内容,n是特征数量,最后一部分是正则化项。我们后续的目的就是来最小化这个损失函数,接下来就是优化J(θ),使其最小化。
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)
结果:
<tf.Tensor 'loss:0' shape=() dtype=string>
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
接下来就是递归5000次,直到收敛:
for i in range(5000):
_, movie_summary = sess.run([train, summaryMerged])
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) + rating_mean
errors = np.sqrt(np.sum((predicts - rating)**2))
# sqrt(arr) ,计算各元素的平方根
errors
我得到的error为4045.411568958254。
最后我们可以尝试输出我们想要的电影推荐了:
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_df.iloc[i]['title']))
idx += 1
if idx == 20:break
我们可以输入用户的ID,然后就可以得到如下的电影推荐输出:
您要向哪位用户进行推荐呢?请输入用户编号:(smaller than 672)666 ==============================为该用户推荐的评分最高的20部电影是:=============================== score: 5.421, movie name: Caveman (1981) score: 5.116, movie name: Daniel Tosh: Completely Serious (2007) score: 4.867, movie name: Ben X (2007) score: 4.737, movie name: Pirate Movie, The (1982) score: 4.721, movie name: G.O.R.A. (2004) score: 4.692, movie name: Ben-hur (2016) score: 4.674, movie name: Ricky Gervais Live 3: Fame (2007) score: 4.655, movie name: Hands in the Air (2010) score: 4.634, movie name: Robin Williams: Weapons of Self Destruction (2009) score: 4.625, movie name: Ricky Gervais Live: Animals (2003) score: 4.604, movie name: Frozen Planet (2011) score: 4.595, movie name: The Last Days of Emma Blank (2009) score: 4.556, movie name: And God Created Woman (Et Dieu... créa la femme) (1956) score: 4.508, movie name: Absolute Giganten (1999) score: 4.445, movie name: Paris, France (1993) score: 4.429, movie name: Cutting Edge: The Magic of Movie Editing, The (2004) score: 4.418, movie name: I'm No Angel (1933) score: 4.390, movie name: Survive and Advance (2013) score: 4.358, movie name: Alien Escape (1995) score: 4.357, movie name: Pervert's Guide to Cinema, The (2006)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。