推荐系统中的矩阵分解(一)(ALS,SVD,BiasdSVD,SVD ++,surprise工具)

矩阵分解在推荐系统中的位置

首先,我们来看看矩阵分解在推荐系统中的位置,矩阵分解的思想属于协同过滤,推荐系统中的主流思想之一。
在这里插入图片描述
基于领域的推荐和基于模型的推荐的区别在于:

  • 基于邻域的协同过滤包括UserCF, ItemCF,将用户的所有数据读入到内存中进行运算,也称之为基于内存的协同过滤(Memory-based)。数据量少的情况下,可以在线实时推荐。
  • 基于模型的推荐(Model-based),采用机器学习的方式,分成训练集和测试集。离线训练时间比较长,但训练完成后,推荐过程比较快。

推荐系统应用的两大场景:

  • 评分预测(主要用于评价网站)矩阵分解主要应用在此处
  • TOP-N推荐 (常用于购物网站,拿不到用户的显性评分,通过隐式反馈给用户推荐的前n个item的列表)

评分矩阵分解

在这里插入图片描述
评分矩阵往往是稀疏的,我们需要根据已有的评分来估计出评分矩阵中空缺的部分,使得评分矩阵能够反映用户的喜欢程度,同时我们也可以将预测出用户评分前N个推荐给用户。
如何从评分矩阵中分解出User矩阵和Item矩阵,只有左侧的R的某些值是已知的,user矩阵和item矩阵都是未知的,学习出User矩阵和Item矩阵,使得User矩阵*Item矩阵与评分矩阵中已知的评分差异最小 => 最优化问题。

什么是矩阵分解

r u i r_{ui} rui表示用户u 对item i 的评分,当 >0时,表示有评分,当=0时,表示没有评分
x u x_u xu表示用户u 的向量,k维列向量
y i y_i yi表示item i 的向量,k维列向量
用户矩阵X,用户数N
X = [ x 1 , x 2 , . . . , x N ] X = [x_1,x_2,...,x_N] X=[x1,x2,...,xN]
商品矩阵Y,商品数为M
Y = [ y 1 , y 2 , . . . , y M ] Y = [y_1,y_2,...,y_M] Y=[y1,y2,...,yM]
用户向量与物品向量的内积,表示用户u 对物品i 的预测评分,矩阵的目标函数:
min ⁡ X , Y ∑ r u i ≠ 0 ( r u i − x u T y i ) 2 + λ ( ∑ u ∥ x u ∥ 2 2 + ∑ i ∥ y i ∥ 2 2 ) \mathop {\min }\limits_{X,Y} \sum\limits_{{r_{ui}} \ne 0} {{{\left( {{r_{ui}} - x_u^T{y_i}} \right)}^2}} + \lambda \left( {\sum\limits_u {\left\| {{x_u}} \right\|_2^2 + } \sum\limits_i {\left\| {{y_i}} \right\|_2^2} } \right) X,Yminrui=0(ruixuTyi)2+λ(uxu22+iyi22)
(L2正则项,保证数值计算稳定性,防止过拟合)

目标函数最优化问题的工程解法:

  • ALS,Alternating Least Squares,交替最小二乘法
  • SGD,Stochastic Gradient Descent,随机梯度下降

ALS算法

ALS, Alternative Least Square, ALS,交替最小二乘法

  • Step1,固定Y 优化X

  • Step2,固定X 优化Y

  • 重复Step1和2,直到X 和Y 收敛。每次固定一个矩阵,优化另一个矩阵,都是最小二乘问题

  • step1. 固定Y优化X
    min ⁡ X u ∑ r u i ≠ 0 ( r u i − x u T y i ) 2 + λ ∑ u ∥ x u ∥ 2 2 \mathop {\min }\limits_{{X_u}} \sum\limits_{{r_{ui}} \ne 0} {{{\left( {{r_{ui}} - x_u^T{y_i}} \right)}^2}} + \lambda \sum\limits_u {\left\| {{x_u}} \right\|_2^2} Xuminrui=0(ruixuTyi)2+λuxu22
    将目标函数转化为矩阵表达式:
    J ( x u ) = ( R u − Y u T x u ) T ( R u − Y u T x u ) + λ x u T x u J({x_u}) = {\left( {{R_u} - Y_u^T{x_u}} \right)^T}\left( {{R_u} - Y_u^T{x_u}} \right) + \lambda x_u^T{x_u} J(xu)=(RuYuTxu)T(RuYuTxu)+λxuTxu
    R u = [ r u i 1 , … , r u i m ] T {R_u} = {[{r_{u{i_1}}}, \ldots ,{r_{u{i_m}}}]^T} Ru=[rui1,,ruim]T用户u 对m个物品的评分
    Y u = [ y i 1 , … , y i m ] {Y_u} = [{y_{{i_1}}}, \ldots ,{y_{{i_m}}}] Yu=[yi1,,yim]m 个物品的向量

  • 对目标函数J关于xu 求梯度,并令梯度为零,得
    ∂ J ( x u ) ∂ x u = − 2 Y u ( R u − Y u T x u ) + 2 λ x u = 0 \frac{{\partial J({x_u})}}{{\partial {x_u}}} = - 2{Y_u}\left( {{R_u} - Y_u^T{x_u}} \right) + 2\lambda {x_u} = 0 xuJ(xu)=2Yu(RuYuTxu)+2λxu=0
    求解后可得:
    x u = ( Y u Y u T + λ I ) − 1 Y u R u {x_u} = {\left( {{Y_u}Y_u^T + \lambda I} \right)^{ - 1}}{Y_u}{R_u} xu=(YuYuT+λI)1YuRu

SGD算法

梯度下降法:
h θ ( x ) = θ 0 + θ 1 x 1 + θ 2 x 2 + ⋯ + θ n x n {h_\theta }(x) = {\theta _0} + {\theta _1}{x_1} + {\theta _2}{x_2} + \cdots + {\theta _n}{x_n} hθ(x)=θ0+θ1x1+θ2x2++θnxn
用它来模拟y,需要将损失函数最小化
损失函数:
J ( Θ ) = 1 2 ∑ i = 1 m ( h θ ( x ) − y ) 2 J(\Theta ) = \frac{1}{2}\sum\limits_{i = 1}^m {{{\left( {{h_\theta }(x) - y} \right)}^2}} J(Θ)=21i=1m(hθ(x)y)2
a表示学习率(步长) Θ 1 = Θ 0 − α ∇ J ( Θ ) {\Theta _1} = {\Theta _0} - \alpha \nabla J(\Theta ) Θ1=Θ0αJ(Θ)
梯度下降法的更新过程:(更新每个特征参数,j=0…n)
θ j = θ j − α ∂ ∂ θ j J ( Θ ) ∂ ∂ θ j J ( Θ ) = ∂ ∂ θ j 1 2 ( h θ ( x ) − y ) 2 l = 2 ⋅ 1 2 ( h θ ( x ) − y ) ⋅ ∂ ∂ θ j ( h θ ( x ) − y ) = ( h θ ( x ) − y ) ⋅ ∂ ∂ θ j ( ∑ i = 0 n θ i x i − y ) = ( h θ ( x ) − y ) x j \begin{array}{l} {\theta _j} = {\theta _j} - \alpha \frac{\partial }{{\partial {\theta _j}}}J(\Theta )\\ \frac{\partial }{{\partial {\theta _j}}}J(\Theta ) = \frac{\partial }{{\partial {\theta _j}}}\frac{1}{2}{({h_\theta }(x) - y)^2} {l} = 2 \cdot \frac{1}{2}({h_\theta }(x) - y) \cdot \frac{\partial }{{\partial {\theta _j}}}({h_\theta }(x) - y)\\ = \left( {{h_\theta }(x) - y} \right) \cdot \frac{\partial }{{\partial {\theta _j}}}\left( {\sum\limits_{i = 0}^n {{\theta _i}} {x_i} - y} \right)\\ = \left( {{h_\theta }(x) - y} \right){x_j} \end{array} θj=θjαθjJ(Θ)θjJ(Θ)=θj21(hθ(x)y)2l=221(hθ(x)y)θj(hθ(x)y)=(hθ(x)y)θj(i=0nθixiy)=(hθ(x)y)xj

SVD矩阵分解在推荐系统中的应用及其扩展

奇异值分解SVD

矩阵分解中的问题

  • 很多矩阵都是非对称的
  • 矩阵A不是方阵,即维度为m*n

我们可以将它转化为对称的方阵,因为:
A A T A{A^T} AAT A T A {A^T}A ATA是对称的方阵
我们可以将A和A的转置矩阵进行相乘,得到对称方阵:
A A T = P Λ 1 P T A T A = Q Λ 2 Q T \begin{array}{l} A{A^T} = P{\Lambda _1}{P^T}\\ {A^T}A = Q{\Lambda _2}{Q^T} \end{array} AAT=PΛ1PTATA=QΛ2QT
此时 Λ 1 {\Lambda _1} Λ1 Λ 2 {\Lambda _2} Λ2均为对角矩阵,具有相同的非零特征值。

假设这些特征值为 σ 1 , σ 2 , … , σ k {\sigma _1},{\sigma _2}, \ldots ,{\sigma _k} σ1,σ2,,σk,k不超过m和n,也就是k<=min(m,n)
此时矩阵A的特征值: λ 1 = σ 1 , λ 2 = σ 2 , … , λ k = σ k {\lambda _1} = \sqrt {{\sigma _1}} ,{\lambda _2} = \sqrt {{\sigma _2}} , \ldots ,{\lambda _k} = \sqrt {{\sigma _k}} λ1=σ1 ,λ2=σ2 ,,λk=σk

我们可以得到为奇异值分解:
A = P Λ Q T A = P\Lambda {Q^T} A=PΛQT
P为左奇异矩阵,mxm维
Q为右奇异矩阵,n*n维
Λ对角线上的非零元素为特征值λ1, λ2, … , λk
在推荐系统中
左奇异矩阵:User矩阵
右奇异矩阵:Item矩阵

但是传统的SVD不适用于推荐系统,主要有以下几个方面

  • SVD分解要求矩阵是稠密的 => 矩阵中的元素不能有缺失
  • 所以,类似于数据清洗,我们需要先对矩阵中的缺失元素进行补全
  • 先有鸡,还是先有蛋。实际上传统SVD更适合做降维

存在的问题:

  • 矩阵往往是稀疏的,大量缺失值 => 计算量大
  • 填充方式简单粗暴 => 噪音大

因此有以下三种SVD的变种算法用于推荐系统中

FunkSVD算法

FunkSVD算法思想:

  • 我们需要设置k,来对矩阵近似求解
  • 矩阵补全以后,再预测,实际上噪音大。矩阵分解之后的还原,只需要关注与原来矩阵中有值的位置进行对比即可,不需要对所有元素进行对比

解决思路:
避开稀疏问题,而且只用两个矩阵进行相乘: M m × n ≈ P m × k T Q k × n {M_{m \times n}} \approx P_{m \times k}^TQ_{k \times n}^{} Mm×nPm×kTQk×n
损失函数 = P和Q矩阵乘积得到的评分,与实际用户评分之差
让损失函数最小化 => 最优化问题

FunkSVD算法步骤:

  • 最小化损失函数: ∑ i , j ( m i j − q j T p i ) 2 \sum\limits_{i,j} {{{\left( {{m_{ij}} - q_j^T{p_i}} \right)}^2}} i,j(mijqjTpi)2
  • 为了防止过拟合,增加正则项
    arg ⁡ min ⁡ p i q j ∑ ( i , j ) ∈ K ( m i j − q j T p i ) 2 + λ ( ∥ p i ∥ 2 2 + ∥ q j ∥ 2 2 ) \arg \mathop {\min }\limits_{{p_i}{q_j}} \sum\limits_{(i,j) \in K} {{{\left( {{m_{ij}} - q_j^T{p_i}} \right)}^2}} + \lambda \left( {\left\| {{p_i}} \right\|_2^2 + \left\| {{q_j}} \right\|_2^2} \right) argpiqjmin(i,j)K(mijqjTpi)2+λ(pi22+qj22)

1,通过梯度下降法,求解P和Q使得损失函数最小化
2,通过P和Q将矩阵补全
3,针对某个用户i,查找之前值缺失的位置,按照补全值从大到小进行推荐

BiasSVD算法

由于用户有自己的偏好,比如有些用户打分偏高;并且商品也有自己的偏好,比如商品的质量好
因此有了biasSVD算法,考虑到用户的偏好与商品的偏好
将与个性化无关的部分,设置为偏好(Bias)部分
b i j = μ + b i + b j {b_{ij}} = \mu + {b_i} + {b_j} bij=μ+bi+bj
μ:所有记录的整体平均数
bi:用户偏好(与商品无关)
bj:商品偏好(与用户无关

优化目标函数:
arg ⁡ min ⁡ p i q j ∑ ( i , j ) ∈ K ( m i j − μ − b i − b j − q j T p i ) 2 + λ ( ∥ p i ∥ 2 2 + ∥ q j ∥ 2 2 + ∥ b i ∥ 2 2 + ∥ b j ∥ 2 2 ) \arg \mathop {\min }\limits_{{p_i}{q_j}} \sum\limits_{(i,j) \in K} {{{\left( {{m_{ij}} - \mu - {b_i} - {b_j} - q_j^T{p_i}} \right)}^2}} + \lambda \left( {\left\| {{p_i}} \right\|_2^2 + \left\| {{q_j}} \right\|_2^2 + \left\| {{b_i}} \right\|_2^2 + \left\| {{b_j}} \right\|_2^2} \right) argpiqjmin(i,j)K(mijμbibjqjTpi)2+λ(pi22+qj22+bi22+bj22)
在迭代过程中,bi,bj的初始值可以设置为0向量,然后进行迭代:
b i = b i + α ( m i j − μ − b i − b j − q j T p i − λ b i ) b j = b j + α ( m i j − μ − b i − b j − q j T p i − λ b j ) \begin{array}{l} {b_i} = {b_i} + \alpha \left( {{m_{ij}} - \mu - {b_i} - {b_j} - q_j^T{p_i} - \lambda {b_i}} \right)\\ {b_j} = {b_j} + \alpha \left( {{m_{ij}} - \mu - {b_i} - {b_j} - q_j^T{p_i} - \lambda {b_j}} \right) \end{array} bi=bi+α(mijμbibjqjTpiλbi)bj=bj+α(mijμbibjqjTpiλbj)
最终得到P和Q

SVD++算法

SVD++算法原理:
在BiasSVD算法基础上进行了改进,考虑用户的隐式反馈

  • 隐式反馈:没有具体的评分,但可能有点击,浏览等行为
  • 对于某一个用户i,假设他的隐式反馈item集合为I(i)
  • 用户i对商品j对应的隐式反馈修正值为 c i j c_{ij} cij
  • 用户i所有的隐式反馈修正值之和为 ∑ s ∈ N ( i ) c s j \sum\limits_{s \in N(i)} {{c_{sj}}} sN(i)csj
  • 优化目标函数:
    arg ⁡ min ⁡ p i q j ∑ ( i , j ) ∈ K ( m i j − μ − b i − b j − q j T p i − q j T ∣ I ( i ) ∣ − 1 2 ∑ s ∈ I ( i ) y s ) 2 + λ ( ∥ p i ∥ 2 2 + ∥ q j ∥ 2 2 + ∥ b i ∥ 2 2 + ∥ b j ∥ 2 2 + ∑ s ∈ I ( i ) ∥ y s ∥ 2 ) \arg \mathop {\min }\limits_{{p_i}{q_j}} \sum\limits_{(i,j) \in K} {{{\left( {{m_{ij}} - \mu - {b_i} - {b_j} - q_j^T{p_i} - q_j^T{{\left| {I(i)} \right|}^{ - \frac{1}{2}}}\sum\limits_{s \in I(i)} {{y_s}} } \right)}^2}} + \lambda \left( {\left\| {{p_i}} \right\|_2^2 + \left\| {{q_j}} \right\|_2^2 + \left\| {{b_i}} \right\|_2^2 + \left\| {{b_j}} \right\|_2^2 + \sum\limits_{s \in I(i)} {{{\left\| {{y_s}} \right\|}^2}} } \right) argpiqjmin(i,j)KmijμbibjqjTpiqjTI(i)21sI(i)ys2+λpi22+qj22+bi22+bj22+sI(i)ys2
    在考虑用户隐式反馈的情况下,最终得到P和Q

surprise工具简介

biasSVD算法
使用Surprise工具中的SVD
参数:

  • n_factors: k值,默认为100
  • n_epochs:迭代次数,默认为20
  • biased:是否使用biasSVD,默认为True
  • verbose:输出当前epoch,默认为False
  • reg_all:所有正则化项的统一参数,默认为0.02
  • reg_bu:bu的正则化参数,reg_bi:bi的正则化参数
  • reg_pu:pu的正则化参数,reg_qi:qi的正则化参数

funkSVD算法
使用Surprise工具中的SVD
参数:

  • n_factors: k值,默认为100
  • n_epochs:迭代次数,默认为20
  • biased:是否使用biasSVD,设置为False
  • verbose:输出当前epoch,默认为False
  • reg_all:所有正则化项的统一参数,默认为0.02
  • reg_bu:bu的正则化参数,reg_bi:bi的正则化参数
  • reg_pu:pu的正则化参数,reg_qi:qi的正则化参数

SVD++算法
使用Surprise工具中的SVDpp
参数:

  • n_factors: k值,默认为20
  • n_epochs:迭代次数,默认为20
  • verbose:输出当前epoch,默认为False
  • reg_all:所有正则化项的统一参数,默认为0.02
  • reg_bu:bu的正则化参数,reg_bi:bi的正则化参数
  • reg_pu:pu的正则化参数,reg_qi:qi的正则化参数
  • reg_yj:yj的正则化参数

利用surprise工具预测movielens简单数据集(SVD,biasSVD,SVD++)

from surprise import Dataset
from surprise import Reader
from surprise import BaselineOnly, KNNBasic, NormalPredictor
from surprise import accuracy
from surprise.model_selection import KFold, split
from surprise import SVD,SVDpp
#import pandas as pd

# 数据读取
reader = Reader(line_format='user item rating timestamp', sep=',', skip_lines=1)
data = Dataset.load_from_file('./ratings.csv', reader=reader)
#rain_set = data.build_full_trainset()
train_s,test_s = split.train_test_split(data, train_size=0.8)

algo1 = SVD()
algo2 = SVD(biased = False)
algo3 = SVDpp()

print('SVDbias结果')
algo1.fit(train_s)
pre = algo1.predict(test_s)
accuracy.rmse(pre,verbose=True)
print('SVD结果')
algo2.fit(train_s)
pre = algo2.predict(test_s)
accuracy.rmse(pre,verbose=True)
print('SVD++结果')
algo3.fit(train_s)
pre = algo3.predict(test_s)
accuracy.rmse(pre,verbose=True)

得到结果:RMSE: 0.8321 SVD结果 RMSE: 0.8540 SVD++结果 RMSE: 0.8198
可以看到SVD++预测的效果最好,但是在训练过程中SVD++所要花费的时间也是最长的。

版权声明:本文为博主原创文章,遵循 C 版权协议,转载请附上原文出处链接和本声明。

  • 9
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值