吴恩达老师机器学习作业-ex8(推荐系统)

导入库并读取数据

因为这次的数据是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会进行怎样的操作呢?

当最小化代价函数的时候,只有\frac{\lambda }{2}\sum_{j=1}^{n_{u}}\sum_{k=1}^{n}(\theta _{k}^{(j)})^{2}这一项可以影响代价函数,因此为了保证代价函数足够小,会将\theta都赋值为0,那么用户E对所有电影的评分都为0,这样就会没有任何意义。

为了避免这种情况的发生,我们可以对数据进行均值归一化,也就是先按行算出评分的平均值,然后Y=Y-\mu。拿新的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

代价函数

J(\theta ,x)=\frac{1}{2}\sum_{(i,j):r(i,j)=1}^{}((\theta ^{(j)})^{T}X^{(i)}-y^{(i,j)})^{2}+\frac{\lambda }{2}\sum_{i=1}^{n_{m}}\sum_{k=1}^{n}(x_{k}^{(i)})^{2}+\frac{\lambda }{2}\sum_{j=1}^{n_{u}}\sum_{k=1}^{n}(\theta _{k}^{(j)})^{2}

#代价函数
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])

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值