推荐系统——矩阵分解&FM

矩阵分解

隐语义模型与矩阵分解

之所以我们提出隐语义模型与矩阵分解,原因就是[[协同过滤]]存在泛化能力弱的问题
而对于隐语义模型而言,我们可以利用隐向量来代表隐藏信息
此外,也可以在一定程度上弥补[[协同过滤]]处理稀疏矩阵能力不足的情况

隐语义模型

隐语义模型主要在于可以挖掘用户和物品的潜在特征来联系不同的用户和物品,接着对不同的用户和item进行聚类
可以举个例子,如果用户A喜欢看侦探小说、科普图书以及一些计算机技术书,而B喜欢数学和机器学习方面。

  • 对于UserCF而言,系统会先找到和其看了相同书的其他用户,然后给新用户推荐其他用户看的书
  • 对于ItemCF而言,系统会找到和新用户已经看的书相似的书(在这里所谓的相似并没有用到隐语义,可能只是简单的通过书籍的评分来寻找相似),然后给用户推荐这些书籍
    那么隐语义模型会尝试将用户兴趣和书进行归类,当用户来的时候会将用户的兴趣分类,再从兴趣分类中挑选他可能喜欢的书籍。

可以再使用一个对音乐评分的例子来看一下隐特征矩阵的含义:
A喜欢带有小清新,吉他伴奏,王菲的歌曲,如果一首歌正好是王菲唱的,并且是吉他伴奏的小清新,那么就可以将这首歌推荐给这个用户,所以这里是三个标签🏷连接起了用户和歌曲。又每首歌中所包含的元素不尽相同,因此,我们可以去找如下两个矩阵

  1. 潜在因子——用户矩阵

    小清新重口味优雅伤感五月天
    0.60.80.10.1
    0.100.90.1
    0.50.70.90.9
  2. 潜在因子——音乐矩阵P
    表示每种音乐中含有各种元素的成分,如下表中,音乐A是一个偏小清新的音乐,含有小清新的Latent Factor的成分是0.9,重口味的成分是0.1,优雅成分0.2

    小清新重口味优雅伤感五月天
    乐A0.90.10.20.4
    乐B0.50.60.10.9
    乐C00.60.10.2

那么有了以上矩阵,我们可以认为张三对音乐A的喜欢程度为
0.6 ∗ 0.9 + 0.8 ∗ 0.1 + 0.1 ∗ 0.2 + 0.1 ∗ 0.4 + 0.7 ∗ 0 = 0.69 0.6*0.9+0.8*0.1+0.1*0.2+0.1*0.4+0.7*0 = 0.69 0.60.9+0.80.1+0.10.2+0.10.4+0.70=0.69
基于此,我们也可以得到一个用户——音乐评分的共现矩阵

音乐A音乐B音乐C音乐D
张三0.681.580.280.51
李四0.310.430.470.11
王五1.061.570.730.69

  所以在此例子中,小清新,重口味,优雅这些就可以看作是隐含特征,而我们就可以用这些隐含特征来将用户的兴趣和音乐进行一个分类,其本质即为找到用户/音乐的一个隐向量表达形式,通过该隐向量就可以来进行用户/音乐之间相似度的判定。

但是在实际情况下,我们一般也是只能有最后的用户——物品打分矩阵,并且矩阵会存在很多缺失值如

音乐A音乐B音乐C音乐D
张三0.68??0.51

而对于使用UserCF或者ItemCF去填充也是很麻烦的,对此,我们可以使用[[矩阵分解]]

矩阵分解的原理

  如果我们有用户——物品打分的共线矩阵 Y Y Y(存在缺失值),基于[[矩阵分解]]的原理,我们求出矩阵 P P P Q Q Q有: P × Q = Y P \times Q = Y P×Q=Y

  其中,矩阵乘法将 m × n m\times n m×n的共现矩阵Y分分解为 m × k m \times k m×k的用户矩阵和 k × n k \times n k×n的物品矩阵,其中m为用户的个数,n为物品的个数,而k为隐向量的维度即隐含特征的个数,但是这里的隐含特征变得无法解释,并不是和我们之前矩阵小清新的例子一样是明显可解释的,而对于k而言,k的大小决定了隐向量的表达能力的强弱,k越大,表达信息就越强,划分得就更具体。

  在有了用户矩阵P和物品矩阵Q之后,如果我们想计算用户 u u u对物品 i i i的评分,只需要
P r e f e r e n c e ( u , i ) = r u i = p u T q i = ∑ f = 1 F p u , k q k , i Preference(u, i) = r_{ui} = p^T_uq_i = \sum_{f=1}^Fp_{u,k}q_{k,i} Preference(u,i)=rui=puTqi=f=1Fpu,kqk,i
  其中, p u p_u pu为用户 u u u所对应的隐向量, q i q_i qi为用户 i i i所对应的隐向量

矩阵分解算法的求解

矩阵分解常用方法为[[特征值分解EVD]]与[[奇异值分解SVD]],但是这两种方法在这里并不适用,比如EVD要求分解的矩阵为方阵,但是对于用户——物品打分矩阵而言,不一定是方阵的形式,而对于SVD分解计算机复杂度非常高

Basic SVD

Funk-SVD:把求解上面两个矩阵的参数问题转换成一个最优化问题,可以通过训练集里面的观察值利用最小化来学习用户矩阵和物品矩阵

  如果我们想计算用户 u u u对物品 i i i的评分,可以使用 P r e f e r e n c e ( u , i ) = r u i = p u T q i = ∑ f = 1 F p u , k q k , i Preference(u, i) = r_{ui} = p^T_uq_i = \sum_{f=1}^Fp_{u,k}q_{k,i} Preference(u,i)=rui=puTqi=f=1Fpu,kqk,i
而我们一般只会有 r u i r_{ui} rui的真实数据,并没有 p u p_u pu q i q_i qi,所以基于修正的思想,我们可以初始化 p u R q i p_u^Rq_i puRqi,然后计算出 r ^ u i = p u T q i \hat{r}_{ui} = p_u^Tq_i r^ui=puTqi,从而得到误差
e u i = r u i − r ^ u i e_{ui} = r_{ui} - \hat{r}_{ui} eui=ruir^ui
接着求出误差平方和
S S E = ∑ u , i e u i 2 = ∑ u , i ( r u i − ∑ k = 1 K p u , k q k , i ) 2 SSE = \sum_{u, i}e_{ui}^2=\sum_{u, i}(r_{ui}-\sum_{k=1}^Kp_{u, k}q_{k, i})^2 SSE=u,ieui2=u,i(ruik=1Kpu,kqk,i)2
有了误差之后,我们可以利用误差进行修正从而使SSE降到最小,转化为一个最优化问题,而目标函数为
min ⁡ q ∗ , p ∗ ∑ ( u , i ) ∈ K ( r u i − p u T q i ) 2 \min_{q^*, p^*}\sum_{(u, i) \in K}(r_{ui} - p_u^Tq_i)^2 q,pmin(u,i)K(ruipuTqi)2

接下来可以使用梯度下降去降低损失,有
p u , k = p u , k − η ( − e u i q k , i ) = p u , k + η e u i q k , i p_{u, k} = p_{u, k} - \eta(-e_{ui}q_{k,i}) = p_{u, k}+\eta e_{ui}q_{k,i} pu,k=pu,kη(euiqk,i)=pu,k+ηeuiqk,i
q k , i = q k , i − η ( − e u i p u , k ) = q k , i + η e u i p u , k q_{k, i} = q_{k, i} - \eta(-e_{ui}p_{u,k}) = q_{k, i}+\eta e_{ui}p_{u,k} qk,i=qk,iη(euipu,k)=qk,i+ηeuipu,k
其中, η \eta η为学习率。

但在实际中,单纯的 r ^ u i = p u T q i \hat{r}_{ui} = p^T_uq_i r^ui=puTqi只能评判一部分属性,对于一个评分系统而言,有些固有属性和用户物品无关,而用户也有有些属性和物品无关,物品也有些属性和用户无关,所以提出了另一种[[LFM]],在原有基础上添加了偏置项。

LFM

LFM在原有基础上加了偏置项,来消除用户和物品打分的偏差,即预测公式如下:
r ^ u i = μ + b u + b i + p u T ⋅ q i \hat{r}_{ui} = \mu + b_u + b_i + p^T_u \cdot q_i r^ui=μ+bu+bi+puTqi
加入了3个偏置项 μ , b u , b i \mu, b_u, b_i μ,bu,bi

  • μ \mu μ:训练集中,也就是那个矩阵Y所有非空元素的平均值。因为可能在一个网站的评价打分中,因为网站的定位和销售物品不同,所以网站的整体打分分布会产生差异,所以 μ \mu μ可以表示网站本身对用户评分的影响。
  • b u b_u bu:用户偏差系数,是用户 u u u所有打分的均值, 可以当作训练参数。这一项表示了用户的评分习惯中和物品没有关系的那种因素
  • b i b_i bi:物品偏差系数,是物品 i i i收到的所有评分的均值,可以当作训练参数。表示了物品接受的评分中和用户没有关系的因素
    而此时添加了偏置系数之后,SSE的形式也需要改变,如果把 b u b_u bu b i b_i bi当作训练参数的话,那么它俩的更新公式为 b u + = η ( e u i − λ b u ) b_u += \eta (e_{ui} - \lambda b_u) bu+=η(euiλbu) b i + = η ( e u i − λ b i ) b_i += \eta(e_{ui} - \lambda b_i) bi+=η(euiλbi)而对于 p u , k p_{u,k} pu,k p k , i p_{k,i} pk,i,导数没有变化,更新公式也没有变化。

实现例子的代码:

import numpy as np
import random

class SVD():
    def __init__(self, rating_data, F=5, alpha=0.1, lmbda=0.1, max_iter=100):
        self.F = F
        self.P = dict()
        self.Q = dict()
        self.rating_data = rating_data
        self.bi = dict()
        self.bu = dict()
        self.mu = 0.0
        self.alpha = alpha
        self.lmbda = lmbda
        self.max_iter = max_iter
        
        cnt = 0
        
        for user, items in self.rating_data.items():
            self.P[user] = [random.random() / np.sqrt(self.F) for i in range(self.F)]
            self.bu[user] = 0
            cnt += len(items)
            
            for item, rating in items.items():
                if item not in self.Q:
                    self.Q[item] = [random.random() / np.sqrt(self.F) for i in range(self.F)]
                    self.bi[item] = 0
        self.mu /= cnt
        
    def train(self):
        for step in range(self.max_iter):
            for user, items in self.rating_data.items():
                for item, rui in items.items():
                    rhat_ui = self.predict(user, item)
                    
                    e_ui = rui - rhat_ui
                    
                    self.bu[user] += self.alpha*(e_ui-self.lmbda*self.bu[user])
                    self.bi[item] += self.alpha*(e_ui-self.lmbda*self.bi[item])
                    
                    # 此处添加了正则化
                    for k in range(self.F):
                        self.P[user][k] += self.alpha*(e_ui*self.Q[item][k] - self.lmbda*self.P[user][k])
                        self.Q[item][k] += self.alpha*(e_ui*self.P[user][k] - self.lmbda*self.Q[item][k])
            self.alpha *= 0.1
        
    def predict(self, user, item):
        return sum(self.P[user][i] * self.Q[item][i] for i in range(self.F)) + self.bu[user] + self.bi[item] + self.mu


def load_data():
    data = {
        'A':{1:5, 2:3, 3:4, 4:4},
        'B':{1:3, 2:1, 3:2, 4:3, 5:3},
        'C':{1:4, 2:3, 3:4, 4:3, 5:5},
        'D':{1:3, 2:3, 3:1, 4:5, 5:4},
        'E':{1:1, 2:5, 3:5, 4:2, 5:1}
    }
    return data

rating_data = load_data()
basicsvd = SVD(rating_data, F=10)
basicsvd.train()
print(item, basicsvd.predict('A', 5))

在这里插入图片描述

FM模型

FM模型的引入

逻辑回归模型及其缺点

一般做CTR预估时最简单的思路即将特征做线性回归(逻辑回归LR),但这样本质上是一个线性模型,由于sigmoid函数是一个单调增函数不会改变里面的线性模型的CTR预测顺序,因此逻辑回归的效果会比较差,即LR的缺点有:

  1. 是一个线性模型
  2. 每个特征对最终输出结果独立,需要手动交叉特征( x i ∗ x j x_i * x_j xixj)

[[二叉交叉项的考虑及改进]]

考虑到做特征交叉较为麻烦,于是考虑所有的二次交叉,于是将目标函数由原来的 y = w 0 + ∑ i = 1 n w i x i y = w_0 + \sum_{i=1}^nw_ix_i y=w0+i=1nwixi改为 y = w 0 + ∑ i = 1 n w i x i + ∑ i n − 1 ∑ j = i + 1 n w i , j x i x j y = w_0 + \sum_{i=1}^nw_ix_i+\sum_{i}^{n-1}\sum_{j=i+1}^nw_{i,j}x_ix_j y=w0+i=1nwixi+in1j=i+1nwi,jxixj

但是针对上式存在一个问题即只有当 x i x_i xi x j x_j xj同时不为0时此二阶交叉项才能起作用
于是提出FM,而FM将上述式子改为 y = w 0 + ∑ i = 1 n w i x i + ∑ i n − 1 ∑ j = i + 1 n < v i , v j > x i x j y = w_0 + \sum_{i=1}^nw_ix_i+\sum_{i}^{n-1}\sum_{j=i+1}^n<v_i,v_j>x_ix_j y=w0+i=1nwixi+in1j=i+1n<vi,vj>xixj

此处的解释为,在这里是对每个 x i x_i xi计算一个 e m b e d d i n g embedding embedding,接着将两个 e m b e d d i n g embedding embedding计算内积即 < v i , v j > <v_i,v_j> <vi,vj>来代替之前的 w i , j w_{i,j} wi,j,好处是这个模型的泛化能力强,即使存在有两个特征从未在训练集中同时出现过,我们也可以计算出它们的 w i , j w_{i,j} wi,j,我们只需要 x i x_i xi和其他的 x k x_k xk同时在训练集中出现过则可计算出 x i x_i xi E m b e d d i n g Embedding Embedding

FM公式的理解

对于FM公式而言,模型表达能力大于LR,只有当交叉项参数 w i j w_{ij} wij全为0的时候,才会退化为LR,而且后面的二阶交叉项的数量一共有 1 + 2 + 3 + ⋯ + n − 1 = n ( n − 1 ) 2 1+2+3+\cdots + n-1 = \frac{n(n-1)}{2} 1+2+3++n1=2n(n1),且任意两个参数之间是独立的。

def 任意一个实对称矩阵([[正定矩阵]]) W W W都存在一个矩阵 V V V,使得 W = V ⋅ V T W = V \cdot V^T W=VVT

y ^ ( X ) = w 0 + ∑ i = 1 n w i x i + ∑ i n − 1 ∑ j = i + 1 n < v i , v j > x i x j \hat{y}(X) = w_0 + \sum_{i=1}^nw_ix_i+\sum_{i}^{n-1}\sum_{j=i+1}^n<v_i,v_j>x_ix_j y^(X)=w0+i=1nwixi+in1j=i+1n<vi,vj>xixj
其中,需要估计的参数有 w 0 ∈ R , w i ∈ R , V ∈ R , < ⋅ , ⋅ > w_0 \in R, w_i \in R, V \in R, <\cdot, \cdot> w0R,wiR,VR,<,>是两个长度为k的向量的内积

对于FM模型而言,在[[二叉交叉项的考虑及改进]]中,我们提出了使用 < ⋅ , ⋅ > <\cdot,\cdot> <,>来代替 w i j w_{ij} wij的改进,从而使二次项的参数数量减少为 k n kn kn个,远远少于多项式模型的二项式参数,此外,参数因子化使得 x h x i x_hx_i xhxi x i x j x_ix_j xixj不再是独立的。

FM模型是一个通用的拟合模型,可以采用不同的损失函数用以解决regression,classification问题。

FM的理解:FM可以用于解决大型稀疏数据中的特征组合问题。对于MF而言,只存在两个两个特征信息,而FM可以将两个特征进行二阶交叉组合,形成一个高阶特征。具体可以参考推荐系统之FM与MF傻傻分不清楚
MF其实算是FM的特例,只有两个特征的特例,给出一个矩阵来帮助理解,希望自己之后看到这个例子可以想起来

user1user2user3
item1123
item2234
item3345

这个是MF的输入矩阵,而转化为FM的格式就变为

user1user2user3item1item2item3score
1001001
1000102
1000013
0101002
0100103
0100014
0011003
0010104
0010015
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值