赞
踩
导入库并读取数据
因为这次的数据是mat文件,需要使用scipy库中的loadmat进行读取数据。
通过对数据类型的分析,发现是字典类型,查看该字典的键,可以发现又X等关键字。
- import numpy as np
- import scipy.io as sio
- from scipy.optimize import minimize
-
- #读取数据
- path_movies = "./ex8_movies.mat"
- data_movies = sio.loadmat(path_movies)
- # print(data_movies.keys())
- Y = data_movies.get("Y")
- R = data_movies.get("R")
-
- path_movieParams = "./ex8_movieParams.mat"
- data_movieParams = sio.loadmat(path_movieParams)
- # print(data_movieParams.keys())
- X = data_movieParams.get("X")
- Theta = data_movieParams.get("Theta")
- num_users = data_movieParams.get("num_users")
- num_movies = data_movieParams.get("num_movies")
- num_features = data_movieParams.get("num_features")
- # print(num_users[0][0])

均值归一化
当对于一个没有对任何电影评过分的用户E会进行怎样的操作呢?
当最小化代价函数的时候,只有这一项可以影响代价函数,因此为了保证代价函数足够小,会将
都赋值为0,那么用户E对所有电影的评分都为0,这样就会没有任何意义。
为了避免这种情况的发生,我们可以对数据进行均值归一化,也就是先按行算出评分的平均值,然后。拿新的Y矩阵再去预测评分,预测完之后,需要将平均值再加回去。这样可以确保第一次位用户进行预测时,每个电影的评分都为平均值。
- #均值归一化
- def standardization(Y,R):
- means = (np.sum(Y,axis=1) / np.sum(R,axis=1)).reshape(-1,1)
- Y_norm = (Y - means) * R
- return Y_norm,means
序列化和解序列化
这里说一下为什么要序列化参数,其实就是改变矩阵的形状,我们后面会用到opt.minimize()这个函数方法,这个优化方法里面需要的参数X0一定得是一维数组(nums,)
- #序列化和解序列化
- def serialization(X,Theta):
- return np.append(X.flatten(),Theta.flatten())
-
- def deserialization(params,nu,nm,nf):
- X = params[:nm[0][0] * nf[0][0]].reshape(nm[0][0],nf[0][0])
- Theta = params[nm[0][0] * nf[0][0]:].reshape(nu[0][0],nf[0][0])
- return X,Theta
代价函数
- #代价函数
- def cost_func(params,nu, nm, nf,Y,R,lamda):
- X, Theta = deserialization(params, nu, nm, nf)
- cost = np.sum(np.power((X @ Theta.T - Y) * R,2))/ 2
- reg1 = np.sum(np.power(X, 2)) * lamda / 2
- reg2 = np.sum(np.power(Theta, 2)) * lamda / 2
- return cost+reg1+reg2
梯度下降
- #梯度下降
- def gradient_descent(params,nu,nm,nf,Y,R,lamda):
- X,Theta = deserialization(params,nu,nm,nf)
- Theta_grad = ((Theta @ X.T - Y.T) * R.T) @ X + lamda * Theta
- X_grad = ((X @ Theta.T - Y) * R) @ Theta + lamda * X
- return serialization(X_grad,Theta_grad)
初始化参数
- #初始化参数
- X = np.random.random((num_movies[0][0],num_features[0][0]))
- Theta = np.random.random((num_users[0][0],num_features[0][0]))
- lamda = 5
- params = serialization(X, Theta)
- Y_normal,means = standardization(Y,R)
优化
- #优化
- res = minimize(x0=params,
- fun=cost_func,
- args=(num_users,num_movies,num_features,Y_normal,R,lamda),
- method="TNC",
- jac=gradient_descent,
- options={'maxiter': 100})
- fit_params = res.x
- fit_X,fit_Theta = deserialization(fit_params,num_users,num_movies,num_features)
添加新用户和评分
- my_ratings = np.zeros((num_movies[0][0], 1))
-
- # 添加电影评分
- my_ratings[9] = 5
- my_ratings[66] = 5
- my_ratings[96] = 5
- my_ratings[121] = 4
- my_ratings[148] = 4
- my_ratings[285] = 3
- my_ratings[490] = 4
- my_ratings[599] = 4
- my_ratings[643] = 4
- my_ratings[958] = 5
- my_ratings[1117] = 3
预测
- #预测
- Y_pre = fit_X @ fit_Theta.T
- y_pre = Y_pre[:,-1] + means.flatten()
- index = np.argsort(-y_pre)
- print(index[:10])
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。