机器学习笔记--推荐系统

1、基于内容的推荐系统

在一个基于内容的推荐系统算法中,我们假设对于我们希望推荐的东西有一些数据,这些数据是有关这些东西的特征。

在我们的例子中,我们可以假设每部电影都有两个特征,如 x 1 x_1 x1 代表电影的浪漫程度, x 2 x_2 x2 代表电影的动作程度。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oiwKr6Mb-1691740503051)(https://note.youdao.com/yws/res/2223/3A738B499DFE471F81ADE6CC733897D1)]

约定:

θ ( j ) \theta^{(j)} θ(j) 用户 j 的参数向量

x ( i ) x^{(i)} x(i) 电影 i 的特征向量

对于用户 j 和电影 i ,我们预测评分为: ( θ ( j ) ) T x ( i ) \left(\theta^{(j)}\right)^{T} x^{(i)} (θ(j))Tx(i)

假设我们采用线性回归模型,针对用户 j ,该线性回归模型的代价为预测误差的平方和,加上正则化项:

min ⁡ θ ( j ) 1 2 ∑ i : r ( i , j ) = 1 ( ( θ ( j ) ) T x ( i ) − y ( i , j ) ) 2 + λ 2 ( θ k ( j ) ) 2 \min _{\theta(j)} \frac{1}{2} \sum_{i: r(i, j)=1}\left(\left(\theta^{(j)}\right)^{T} x^{(i)}-y^{(i, j)}\right)^{2}+\frac{\lambda}{2}\left(\theta_{k}^{(j)}\right)^{2} θ(j)min21i:r(i,j)=1((θ(j))Tx(i)y(i,j))2+2λ(θk(j))2

其中 i : r ( i , j ) i:r(i, j) i:r(i,j) 表示我们只计算那些用户 j 评过分的电影。

对于所有用户,代价函数为:

min ⁡ θ ( 1 ) , … , θ ( n u ) 1 2 ∑ j = 1 n u ∑ i : r ( i , j ) = 1 ( ( θ ( j ) ) T x ( i ) − y ( i , j ) ) 2 + λ 2 ∑ j = 1 n u ∑ k = 1 n ( θ k ( j ) ) 2 \min _{\theta^{(1), \ldots, \theta^{\left(n_{u}\right)}}} \frac{1}{2} \sum_{j=1}^{n_{u}} \sum_{i: r(i, j)=1}\left(\left(\theta^{(j)}\right)^{T} x^{(i)}-y^{(i, j)}\right)^{2}+\frac{\lambda}{2} \sum_{j=1}^{n_{u}} \sum_{k=1}^{n}\left(\theta_{k}^{(j)}\right)^{2} θ(1),,θ(nu)min21j=1nui:r(i,j)=1((θ(j))Tx(i)y(i,j))2+2λj=1nuk=1n(θk(j))2
求偏导,得到梯度下降更新公式

θ k ( j ) : = θ k ( j ) − α ∑ i : r ( i , j ) = 1 ( ( θ ( j ) ) T x ( i ) − y ( i , j ) ) x k ( i ) (  for  k = 0 ) θ k ( j ) : = θ k ( j ) − α ( ∑ i : r ( i , j ) = 1 ( ( θ ( j ) ) T x ( i ) − y ( i , j ) ) x k ( i ) + λ θ k ( j ) ) (  for  k ≠ 0 ) \begin{gathered} \theta_{k}^{(j)}:=\theta_{k}^{(j)}-\alpha \sum_{i: r(i, j)=1}\left(\left(\theta^{(j)}\right)^{T} x^{(i)}-y^{(i, j)}\right) x_{k}^{(i)} \quad(\text { for } k=0) \\ \theta_{k}^{(j)}:=\theta_{k}^{(j)}-\alpha\left(\sum_{i: r(i, j)=1}\left(\left(\theta^{(j)}\right)^{T} x^{(i)}-y^{(i, j)}\right) x_{k}^{(i)}+\lambda \theta_{k}^{(j)}\right) \quad(\text { for } k \neq 0) \end{gathered} θk(j):=θk(j)αi:r(i,j)=1((θ(j))Tx(i)y(i,j))xk(i)( for k=0)θk(j):=θk(j)α i:r(i,j)=1((θ(j))Tx(i)y(i,j))xk(i)+λθk(j) ( for k=0)

2、协同过滤

在之前的基于内容的推荐系统中,对于每一部电影,我们都掌握了可用的特征,使用这些特征训练出了每一个用户的参数。相反地,如果我们拥有用户的参数,我们可以学习得出电影的特征。

但是如果我们既没有用户的参数,也没有电影的特征,这两种方法都不可行了。协同过滤算法可以同时学习这两者。

我们的优化目标便改为同时针对 x x x θ \theta θ 进行

J ( x ( 1 ) , … x ( n m ) , θ ( 1 ) , … , θ ( n u ) ) = 1 2 ∑ ( i : j ) : r ( i , j ) = 1 ( ( θ ( j ) ) T x ( i ) − y ( i , j ) ) 2 + λ 2 ∑ i = 1 n m ∑ k = 1 n ( x k ( j ) ) 2 + λ 2 ∑ j = 1 n u ∑ k = 1 n ( θ k ( j ) ) 2 \begin{aligned} &J\left(x^{(1)}, \ldots x^{\left(n_{m}\right)}, \theta^{(1)}, \ldots, \theta^{\left(n_{u}\right)}\right) \\ &\qquad \begin{aligned} &=\frac{1}{2} \sum_{(i: j): r(i, j)=1}\left(\left(\theta^{(j)}\right)^{T} x^{(i)}-y^{(i, j)}\right)^{2}+\frac{\lambda}{2} \sum_{i=1}^{n_{m}} \sum_{k=1}^{n}\left(x_{k}^{(j)}\right)^{2} \\ &+\frac{\lambda}{2} \sum_{j=1}^{n_{u}} \sum_{k=1}^{n}\left(\theta_{k}^{(j)}\right)^{2} \end{aligned} \end{aligned} J(x(1),x(nm),θ(1),,θ(nu))=21(i:j):r(i,j)=1((θ(j))Tx(i)y(i,j))2+2λi=1nmk=1n(xk(j))2+2λj=1nuk=1n(θk(j))2

对代价函数求偏导数:

x k ( i ) : = x k ( i ) − α ( ∑ j : r ( i , j ) = 1 ( ( θ ( j ) ) T x ( i ) − y ( i , j ) θ k j + λ x k ( i ) ) θ k ( i ) : = θ k ( i ) − α ( ∑ i : r ( i , j ) = 1 ( ( θ ( j ) ) T x ( i ) − y ( i , j ) x k ( i ) + λ θ k ( j ) ) min ⁡ x ( 1 ) , … , x ( n m ) 1 2 ∑ i = 1 n m ∑ j r ( i , j ) = 1 ( ( θ ( j ) ) T x ( i ) − y ( i , j ) ) 2 + λ 2 ∑ i = 1 n m ∑ k = 1 n ( x k ( i ) ) 2 \begin{gathered} x_{k}^{(i)}:=x_{k}^{(i)}-\alpha\left(\sum_{j: r(i, j)=1}\left(\left(\theta^{(j)}\right)^{T} x^{(i)}-y^{(i, j)} \theta_{k}^{j}+\lambda x_{k}^{(i)}\right)\right. \\ \theta_{k}^{(i)}:=\theta_{k}^{(i)}-\alpha\left(\sum_{i: r(i, j)=1}\left(\left(\theta^{(j)}\right)^{T} x^{(i)}-y^{(i, j)} x_{k}^{(i)}+\lambda \theta_{k}^{(j)}\right)\right. \\ \min _{x^{(1)}, \ldots, x^{\left(n_{m}\right)}} \frac{1}{2} \sum_{i=1}^{n_{m}} \sum_{j r(i, j)=1}\left(\left(\theta^{(j)}\right)^{T} x^{(i)}-y^{(i, j)}\right)^{2}+\frac{\lambda}{2} \sum_{i=1}^{n_{m}} \sum_{k=1}^{n}\left(x_{k}^{(i)}\right)^{2} \end{gathered} xk(i):=xk(i)α j:r(i,j)=1((θ(j))Tx(i)y(i,j)θkj+λxk(i))θk(i):=θk(i)α i:r(i,j)=1((θ(j))Tx(i)y(i,j)xk(i)+λθk(j))x(1),,x(nm)min21i=1nmjr(i,j)=1((θ(j))Tx(i)y(i,j))2+2λi=1nmk=1n(xk(i))2

协同过滤算法使用步骤如下:

  1. 初始化 x ( 1 ) , x ( 1 ) , … x ( n m ) , θ ( 1 ) , θ ( 2 ) , … , θ ( n u ) x^{(1)}, x^{(1)}, \ldots x^{(n m)}, \theta^{(1)}, \theta^{(2)}, \ldots, \theta^{\left(n_{u}\right)} x(1),x(1),x(nm),θ(1),θ(2),,θ(nu) 为一些随机小值;

  2. 使用梯度下降算法最小化代价函数;

  3. 在训练完算法后,我们预测 ( θ ( j ) ) T x ( i ) \left(\theta^{(j)}\right)^{T} x^{(i)} (θ(j))Tx(i) 为用户 j 给电影 i 的评分.

3、课后习题

# @Time : 2021/11/3 20:20
# @Author : xiao cong
# @Function : 协同过滤
"""
这一部分,将实现协同过滤学习算法,并将其应用于电影评分数据集。这个数据集由1到5的等级组成。
数据集有 n_u = 943个用户,n_m = 1682部电影。
"""

import matplotlib.pyplot as plt
import numpy as np
from scipy.io import loadmat

data = loadmat("ex8_movies.mat")
# print(data)
Y, R = data["Y"], data["R"]  # Y中0代表用户没有评分
nu, nm = Y.shape[0], Y.shape[1]
'''
矩阵Y(nm, nu)是不同电影的不同用户的评分,行数为电影数目,列数为用户数目。
矩阵R是二进制指示矩阵,R(i, j)=1 表示用户j 对电影i 有评分,R(i, j)=0 表示用户j对电影i没有评分。
'''
print("Y.shape = {}, R.shape = {}".format(Y.shape, R.shape))

print("第一部电影均分 = {}".format(Y[0].sum() / R[0].sum()))

# 评分可视化
fig = plt.figure(figsize=(8, 8 * (1682. / 943.)))
plt.imshow(Y, cmap="rainbow")
plt.colorbar()  # 显示渐进色条
plt.xlabel('Users (%d)' % nu)
plt.ylabel('Movies (%d)' % nm)
plt.show()

# ***********************************************************************************
# 实现协同过滤算法
mat = loadmat("ex8_movieParams.mat")
# print(mat)
X = mat["X"]  # 维度(1682, 10)
Theta = mat["Theta"]  # 维度(943, 10)
nu = int(mat["num_users"])
nu = int(mat["num_movies"])
nf = int(mat["num_features"])

# 为减小数据规模,仅取一部分数据
nu, nm, nf = 4, 5, 3
X = X[:nm, :nf]
Theta = Theta[:nu, :nf]
Y = Y[:nm, :nu]
R = R[:nm, :nu]
print("X.shape = {}, Theta.shape = {}".format(X.shape, Theta.shape))


def serialize(X, Theta):  # 序列化
    return np.r_[X.flatten(), Theta.flatten()]  # 两列接成一列


def deserialize(seq, nu, nm, nf):  # 解序列化
    return seq[:nm * nf].reshape(nm, nf), seq[nm * nf:].reshape(nu, nf)  # 再还原成X, Theta


# 定义损失函数
def cost_function(params, Y, R, nm, nu, nf, Lambda):
    """
    params : 拉成一维之后的参数向量(X, Theta)
    Y : 评分矩阵 (nm, nu)
    R :0-1矩阵,表示用户对某一电影有无评分
    nu : 用户数量
    nm : 电影数量
    nf : 自定义的特征的维度
    Lambda : lambda for regularization
    """
    X, Theta = deserialize(params, nu, nm, nf)
    error = 0.5 * ((np.dot(X, Theta.T) * R - Y) ** 2).sum()
    reg1 = 0.5 * Lambda * (Theta ** 2).sum()  # 协同过滤的参数没有偏置项,故都可以正则化
    reg2 = 0.5 * Lambda * (X ** 2).sum()
    return error + reg1 + reg2


print(cost_function(serialize(X, Theta), Y, R, nm, nu, nf, Lambda=0))
print(cost_function(serialize(X, Theta), Y, R, nm, nu, nf, Lambda=1.5))


# 协调过滤梯度下降
def gradient(params, Y, R, nm, nu, nf, Lambda):
    """
    计算X和Theta的梯度,并序列化输出。
    """
    X, Theta = deserialize(params, nu, nm, nf)
    X_grad = ((X @ Theta.T - Y) * R) @ Theta + Lambda * X
    Theta_grad = ((X @ Theta.T) * R - Y).T @ X + Lambda * Theta
    # 计算时注意向量维度
    return serialize(X_grad, Theta_grad)


# 梯度检验
def gradient_checking(params, Y, R, nm, nu, nf, Lambda):
    grad = gradient(params, Y, R, nm, nu, nf, Lambda)  # 求导得到的梯度
    gradapprox = np.zeros(params.shape)  # 记录计算得到的近似梯度
    e = 0.0001

    for i in range(len(params)):
        plus = params.copy()  # 不可直接赋值,否则会影响params
        plus[i] = plus[i] + e
        minus = params.copy()
        minus[i] = minus[i] - e
        loss1 = cost_function(plus, Y, R, nm, nu, nf, Lambda)
        loss2 = cost_function(minus, Y, R, nm, nu, nf, Lambda)
        gradapprox[i] = (loss1 - loss2) / (2 * e)
        # print(gradapprox[i])

    diff = np.linalg.norm(gradapprox - grad) / np.linalg.norm(gradapprox + grad)  # 范数
    # 这里np.linalg.norm 意思是求向量模长
    print('diff = {}'.format(diff))
    # If your backpropagation implementation is correct,
    # the relative difference will besmaller than 10e-9 (assume epsilon=0.0001)


gradient_checking(serialize(X, Theta), Y, R, nm, nu, nf, Lambda=0)

# **************************************************************************
movies = []
f = open("movie_ids.txt", "r", encoding="utf_8")
for line in f:
    token = line.strip().split(' ')  # 先去除末尾换行符,再按空格分隔
    movies.append(' '.join(token[1:]))

my_ratings = np.zeros((1682, 1))

my_ratings[0] = 4  # 初始化部分评分
my_ratings[97] = 2
my_ratings[6] = 3
my_ratings[11] = 5
my_ratings[53] = 4
my_ratings[63] = 5
my_ratings[65] = 3
my_ratings[68] = 5
my_ratings[182] = 4
my_ratings[225] = 5
my_ratings[354] = 5

for i in range(len(my_ratings)):
    if my_ratings[i] > 0:
        print("{}   {}".format(my_ratings[i][0], movies[i]))

# 将上面新增的用户数据添加到 Y 和 R 中
data = loadmat("ex8_movies.mat")
Y, R = data["Y"], data["R"]

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


# 归一均值化数据
def normalize_rating(Y, R):
    Ymean = (Y.sum(axis=1) / R.sum(axis=1)).reshape(-1, 1)
    Ynorm = (Y - Ymean) * R  # 注意不要归一化未评分的数据
    return Ymean, Ynorm


Ymean, Ynorm = normalize_rating(Y, R)


# 这里随机生成 X 和Theta参数,用函数进行拟合
nm, nu = Y.shape
nf = 10
X = np.random.random((nm, nf))  # 生成(nm, nf)随机浮点数,浮点数范围 : (0,1)
# (1682, 10)
Theta = np.random.random((nu, nf))  # (944, 10)
params = serialize(X, Theta)
Lambda = 10

import scipy.optimize as opt

res = opt.minimize(fun=cost_function,
                   x0=params,
                   args=(Ynorm, R, nm, nu, nf, Lambda),       # 这里用归一化后的数据
                   method='TNC',
                   jac=gradient,
                   options={'maxiter': 100})

ret = res.x

fit_X, fit_Theta = deserialize(ret, nu, nm, nf)  # 这是训练好的参数
print(fit_X.shape, fit_Theta.shape)

# 下面用训练好的参数来预测
prediction = fit_X @ fit_Theta.T
pred_last_user = prediction[:, -1] + Ymean.flatten()  # 注意加上平均值
# print(prediction[:,-1].shape)      # prediction 维度 (1682,)
pred_sorted_idx = np.argsort(pred_last_user)  # 从小到大排列,返回其索引
pred_sorted_idx = pred_sorted_idx[::-1]  # 翻转,从大到小输出

print("Top recommendations for you:")
for i in range(10):
    print("%0.5f    %s" % (pred_last_user[pred_sorted_idx[i]], movies[pred_sorted_idx[i]]))

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
一、机器学习推荐系统课程简介伴随着大数据时代的到来,作为发掘数据规律的重要手段,机器学习已经受到了越来越多的关注。而作为机器学习算法在大数据上的典型应用,推荐系统已成为各行业互联网公司营销体系中不可或缺的一部分,而且已经带来了真实可见的收益。目前,推荐系统机器学习已经成为各大公司的发力重点,众多知名公司(如亚马逊、netflix、facebook、阿里巴巴、京东、腾讯、新浪、头条等)都在着眼于将蕴含在庞大数据中的宝藏发掘出来,懂机器学习算法的大数据工程师也成为了新时代最紧缺的人才。尚硅谷精心打造出了机器学习推荐系统课程,将机器学习理论与推荐系统项目实战并重,对机器学习推荐系统基础知识做了系统的梳理和阐述,并通过电影推荐网站的具体项目进行了实战演练。为有志于增加大数据项目经验、扩展机器学习发展方向的工程师提供最好的学习平台。二、课程内容和目标本课程主要分为两部分,机器学习推荐系统基础,与电影推荐系统项目实战。第一部分主要是机器学习推荐系统基础理论的讲解,涉及到各种重要概念和基础算法,并对一些算法用python做了实现;第二部分以电影网站作为业务应用场景,介绍推荐系统的开发实战。其中包括了如统计推荐、基于LFM的离线推荐、基于模型的实时推荐、基于内容的推荐等多个模块的代码实现,并与各种工具进行整合互接,构成完整的项目应用。通过理论和实际的紧密结合,可以使学员对推荐系统这一大数据应用有充分的认识和理解,在项目实战中对大数据的相关工具和知识做系统的回顾,并且可以掌握基本算法,入门机器学习这一前沿领域,为未来发展提供更多的选择,打开通向算法工程师的大门。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值