别催~ 在加载了 . . .

Recommendation


Recommendation

Question

In this part of the exercise, you will implement the collaborative filtering learning algorithm and apply it to a dataset of movie ratings.2 This dataset consists of ratings on a scale of 1 to 5. The dataset has n**u = 943 users, and n*m = 1682 movies.

理论基础

推荐算法是当今各大IT、科技、视频公司的研究重点,因为这些公司往往有精准投放广告和精准商品推荐的需求。本次采用的是较为基础的协同过滤算法,算法简单,在梯度下降的基础上实现。只需将电影特征参数,用户特征参数作为未知数,构造损失函数,利用梯度下降求得最优值即可。该算法需要有一定的数据集供训练,也就是从许多用户的电影打分评价情况来进行拟合,推测电影特征、用户特征,并进行预测。该算法较为基础,一般需要大量数据才能保证预测的准确度。目前多数公司还是采用神经网络等手段进行推荐算法的实现。

数据读取处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np
import scipy.io as sio
import matplotlib.pyplot as plt

mat=sio.loadmat('Recommendation_movies.mat')
mat.keys()
dict_keys(['__header__', '__version__', '__globals__', 'Y', 'R'])

Y,R=mat['Y'],mat['R']
Y.shape,R.shape
((1682, 943), (1682, 943))

param_mat=sio.loadmat('Recommendation_movieParams.mat')
param_mat.keys()
dict_keys(['__header__', '__version__', '__globals__', 'X', 'Theta', 'num_users', 'num_movies', 'num_features'])
1
2
3
4
5
6
7
8
X,Theta,nu,nm,nf=param_mat['X'],param_mat['Theta'],param_mat['num_users'],param_mat['num_movies'],param_mat['num_features']

X.shape,Theta.shape,nu,nm,nf
((1682, 10),
(943, 10),
array([[943]], dtype=uint16),
array([[1682]], dtype=uint16),
array([[10]], dtype=uint8))
1
2
3
4
5
nu=int(nu)
nm=int(nm)
nf=int(nf)
nu,nm,nf
(943, 1682, 10)

序列化和还原

因为minimize函数必须传入一维数据,所以我们要先将特征参数矩阵序列化,完成训练后再还原

1
2
def serialize(X,Theta):
return np.append(X.flatten(),Theta.flatten())
1
2
3
4
def deserialize(params,nm,nu,nf):
X=params[:nm*nf].reshape(nm,nf)
Theta=params[nm*nf:].reshape(nu,nf)
return X,Theta

损失函数

1
2
3
4
5
6
def costFunction(params,Y,R,nm,nu,nf,lamda):
X,Theta=deserialize(params,nm,nu,nf)
error=0.5*np.square((X@Theta.T-Y)*R).sum()
reg1=0.5*lamda*np.square(X).sum()
reg2=0.5*lamda*np.square(Theta).sum()
return error+reg1+reg2
1
2
3
4
5
6
7
8
9
10
users=4
movies=5
features=3
X_sub=X[:movies,:features]
Theta_sub=Theta[:users,:features]
Y_sub=Y[:movies,:users]
R_sub=R[:movies,:users]
cost1=costFunction(serialize(X_sub,Theta_sub),Y_sub,R_sub,movies,users,features,lamda=0)
cost1
22.224603725685675

梯度下降

1
2
3
4
5
def costGradient(params,Y,R,nm,nu,nf,lamda):
X,Theta=deserialize(params,nm,nu,nf)
X_grad=((X@Theta.T-Y)*R)@Theta+lamda*X
Theta_grad=((X@Theta.T-Y)*R).T@X+lamda*Theta
return serialize(X_grad,Theta_grad)

创建一个测试用用户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
my_ratings=np.zeros((nm,1))
my_ratings[27]=5
my_ratings[28]=5
my_ratings[49]=5
my_ratings[134]=5
my_ratings[140]=5
my_ratings[175]=5
my_ratings[200]=2
my_ratings[203]=4
my_ratings[226]=5
my_ratings[227]=5
my_ratings[228]=5
my_ratings[229]=5
my_ratings[230]=5
my_ratings[342]=5
my_ratings[402]=5
my_ratings[422]=5
my_ratings[448]=5
my_ratings[449]=5

Y=np.c_[Y,my_ratings]
R=np.c_[R,my_ratings!=0]
Y.shape
(1682, 944)

nm,nu=Y.shape

将打分归一化

1
2
3
4
def normalizeRatings(Y,R):
Y_mean=(Y.sum(axis=1)/R.sum(axis=1)).reshape(-1,1)
Y_norm=(Y-Y_mean)*R
return Y_norm,Y_mean
1
Y_norm,Y_mean=normalizeRatings(Y,R)

开始训练

1
2
3
4
X=np.random.random((nm,nf))
Theta=np.random.random((nu,nf))
params=serialize(X,Theta)
lamda=5
1
2
from scipy.optimize import minimize
res=minimize(fun=costFunction,x0=params,args=(Y_norm,R,nm,nu,nf,lamda),method='TNC',jac=costGradient,options={'maxiter':100})
1
2
3
params_fit=res.x
fit_X,fit_Theta=deserialize(params_fit,nm,nu,nf)
Y_pred=fit_X@fit_Theta.T

对测试用用户进行预测并打印结果

我特意令测试用用户针对部分电影打高分,比如星球大战、星际迷航、太空漫步、Alien等科幻、冒险电影。在打分数据较多的情况下,可以看见结果还是比较靠谱,排在前面的有独立日、星战系列、终结者、夺宝奇兵等。因为这些电影带有一定的爱情、浪漫情节、元素,结果同样也推荐了相关的泰坦尼克号等电影。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
y_pred=Y_pred[:,-1]+Y_mean.flatten()
index=np.argsort(-y_pred)
index[:10]
array([ 120, 49, 180, 171, 173, 95, 312, 194, 1466, 209],
dtype=int64)

movies=[]
with open('movie_ids.txt','r',encoding='latin 1')as f:
for line in f:
tokens=line.strip().split(' ')
movies.append(' '.join(tokens[1:]))

len(movies)
1682

for i in range(10):
print(index[i],movies[index[i]],y_pred[index[i]])

120 Independence Day (ID4) (1996) 5.449120842440642
49 Star Wars (1977) 5.352125183811118
180 Return of the Jedi (1983) 5.319959550159248
171 Empire Strikes Back, The (1980) 5.182303379024724
173 Raiders of the Lost Ark (1981) 5.170746823498372
95 Terminator 2: Judgment Day (1991) 5.109846973143337
312 Titanic (1997) 5.042844020713496
194 Terminator, The (1984) 5.026389017143506
1466 Saint of Fort Washington, The (1993) 5.0090202813542275
209 Indiana Jones and the Last Crusade (1989) 5.008614086836323

Site

代码(Jupyter)和所用数据:https://github.com/codeYu233/Study/tree/main/Recommendation

Note

该题与数据集均来源于Coursera上斯坦福大学的吴恩达老师机器学习的习题作业,学习交流用,如有不妥,立马删除


文章作者: codeYu233
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 codeYu233 !
评论
  目录