解决此类问题可以使用线性回归的思想,那么我们的目标就是优化一个θ,来使的θ.T*x的值与实际值y(i,j)相近。公式如下:
选择特征:
第一个式子的目标是优化θ,其中i:r(i,j)=1是指对该用户评价过的电影求和
第二个式子的目标是优化x,其中j:r(i,j)=1是指对某一部电影对评价过它的用户j求和
矢量化计算:
均值归一化:
data2 = loadmat('ex8_movies.mat')
Y = data2['Y']
R = data2['R']
Y.shape,R.shape
def cost(params,Y,R,features):
"""计算代价函数
Params:
params:存放X与Theta数据的narray
Y:电影数量*用户数量的矩阵(包含了每一位用户对所有电影的平分情况)
R:电影数量*用户数量的矩阵(用1表示第i个用户对第j部电影进行了评分)
features:特征数量
return:
J:代价函数"""
Y= np.mat(Y)
R = np.mat(R)
num_movies,num_users = Y.shape
X = np.reshape(params[:num_movies*features],(num_movies,features)) #(1682,10)
Theta = np.reshape(params[num_movies*features:],(num_users,features)) #(943,10)
J = 0
error = np.multiply(X@Theta.T - Y,R) #(1628,943),乘R的原因在于计算评价过的电影的误差
square_error = np.power(error,2)
J = (1/2) * np.sum(square_error)
return J
if __name__ == '__main__':
movies = 5
users = 4
features = 5
X_ = X[:movies,:features]
Theta_ = Theta[:users,:features]
Y_ = Y[:movies,:users]
R_ = R[:movies,:users]
params_ = np.concatenate((np.ravel(X_),np.ravel(Theta_)))
J = cost(params_,Y_,R_,features)
print(J)
def cost(params,Y,R,features):
"""计算代价函数
Params:
params:存放X与Theta数据的narray
Y:电影数量*用户数量的矩阵(包含了每一位用户对所有电影的平分情况)
R:电影数量*用户数量的矩阵(用1表示第i个用户对第j部电影进行了评分)
features:特征数量
return:
J:代价函数
grad:包含X与Theta梯度函数的narray"""
Y= np.mat(Y)
R = np.mat(R)
num_movies,num_users = Y.shape
X = np.reshape(params[:num_movies*features],(num_movies,features)) #(1682,10)
Theta = np.reshape(params[num_movies*features:],(num_users,features)) #(943,10)
J = 0
X_grad = np.zeros((num_movies,features))
Theta_grad = np.zeros((num_users,features))
error = np.multiply(X@Theta.T - Y,R) #(1628,943),乘R的原因在于计算评价过的电影的误差
square_error = np.power(error,2)
J = (1/2) * np.sum(square_error)
X_grad = error@Theta #(1682,10)
Theta_grad = error.T@X #(943,10)
grad = np.concatenate((np.ravel(X_grad),np.ravel(Theta_grad)))
return J,grad
def reg_cost(params,Y,R,features,learning_rate):
"""计算代价函数
Params:
params:存放X与Theta数据的narray
Y:电影数量*用户数量的矩阵(包含了每一位用户对所有电影的平分情况)
R:电影数量*用户数量的矩阵(用1表示第i个用户对第j部电影进行了评分)
features:特征数量
return:
J:代价函数"""
Y= np.mat(Y)
R = np.mat(R)
num_movies,num_users = Y.shape
X = np.reshape(params[:num_movies*features],(num_movies,features)) #(1682,10)
Theta = np.reshape(params[num_movies*features:],(num_users,features)) #(943,10)
J = 0
X_grad = np.zeros((num_movies,features))
Theta_grad = np.zeros((num_users,features))
error = np.multiply(X@Theta.T - Y,R) #(1628,943),乘R的原因在于计算评价过的电影的误差
square_error = np.power(error,2)
J = (1/2) * np.sum(square_error)
J = J + (learning_rate/2)*np.sum(np.power(Theta,2))
J = J + (learning_rate/2)*np.sum(np.power(X,2))
X_grad = error@Theta + (learning_rate*X)#(1682,10)
Theta_grad = error.T@X + (learning_rate*Theta)#(943,10)
grad = np.concatenate((np.ravel(X_grad),np.ravel(Theta_grad)))
return J,grad
with open('movie_ids.txt',encoding= 'gbk') as f:
movie_idx={}
for each_movie in f:
each_movie = each_movie.strip()
tokens = each_movie.split(' ',1)
movie_idx[int(tokens[0])-1] = tokens[1]
ratings = np.zeros((1682, 1)) #添加自己的一列
ratings[0] = 4
ratings[6] = 3
ratings[11] = 5
ratings[53] = 4
ratings[63] = 5
ratings[65] = 3
ratings[68] = 5
ratings[97] = 2
ratings[182] = 4
ratings[225] = 5
ratings[354] = 5
Y_add = np.append(Y,ratings,axis=1)
R_add = np.append(R,ratings!=0,axis=1)
movie_idx[0]
movies_num =Y.shape[0]
user_num =Y.shape[1]
features =10
learning_rate = 10.
X_test = np.random.random(size=(movies_num*features)) #随机初始化
Theta_test = np.random.random(size=(user_num*features))
params_test = np.concatenate((X_test.ravel(),Theta_test.ravel()))
# 均值归一化
Ymean = np.zeros((Y.shape[0],1)) #初始化所有电影的评价得分
Ynorm = np.zeros((Y.shape[0],user_num))
m = Y.shape[0]
for i in range(m):
index = np.where(R[i,:]==1)[0]
Ymean[i] = Y[i,index].mean()
Ynorm[i,index] = Y[i,index]-Ymean[i]
Ynorm.mean()
from scipy.optimize import minimize
fmin = minimize(fun=reg_cost
,x0=params_test
,args=(Ynorm,R_add,features,learning_rate)
,method = 'CG', jac = True,options={'maxiter':100})
fmin
X = np.reshape(fmin.x[:movies_num*features],(movies_num,features))
Theta = np.reshape(fmin.x[movies_num*features:],(user_num,features))
predictions = X@Theta.T #所有的预测值
my_pred = predictions[:,-1].reshape(Ymean.shape[0],1) + Ymean #预测我自己的电影偏好
#获取喜欢电影前十部的索引
inx = np.argsort(my_pred,axis=0)[::-1]
count = 1
for i in range(10):
movie_name = movie_idx[int(inx[i,:])]
print('Top {} movies U might like:{}'.format(count,movie_name))
count+=1
如果当我们的数据集有10000000条数据,那么这个计算量就会非常的大,此时如果再去使用梯度下降,我们会耗费过多的计算力。大数据算法就是用来解决这个问题的。
Stochastic梯度下降算法的思想是首先,随机打乱数据,然后每一次迭代只要拟合一个训练样本即可。其中cost函数发生了变化。
在使用随机梯度下降时,由于我们的θ优化走的是一条迂回的路线,因此我们有可能有时会错失获取最佳θ的机会。面对这个问题,我们可以每迭代1000次就计算一次代价函数,有助于我们选择最好的θ
从时候的数据流当中进行学习
例子:比如你拥有一个快递网站,用户访问你的网站获取将其包裹从A地邮寄到B地的价格(x),然后决定是否邮寄(y)。在线学习算法就是每次一有用户进来就优化一次θ,然后随着用户进来的越来越多,我们的模型会越来越适应消费者的需求。这种方法适用于用户流比较大的网站。