矩阵分解
隐语义模型与矩阵分解
之所以我们提出隐语义模型与矩阵分解,原因就是[[协同过滤]]存在泛化能力弱的问题
而对于隐语义模型而言,我们可以利用隐向量来代表隐藏信息
此外,也可以在一定程度上弥补[[协同过滤]]处理稀疏矩阵能力不足的情况
隐语义模型
隐语义模型主要在于可以挖掘用户和物品的潜在特征来联系不同的用户和物品,接着对不同的用户和item进行聚类
可以举个例子,如果用户A喜欢看侦探小说、科普图书以及一些计算机技术书,而B喜欢数学和机器学习方面。
- 对于UserCF而言,系统会先找到和其看了相同书的其他用户,然后给新用户推荐其他用户看的书
- 对于ItemCF而言,系统会找到和新用户已经看的书相似的书(在这里所谓的相似并没有用到隐语义,可能只是简单的通过书籍的评分来寻找相似),然后给用户推荐这些书籍
那么隐语义模型会尝试将用户兴趣和书进行归类,当用户来的时候会将用户的兴趣分类,再从兴趣分类中挑选他可能喜欢的书籍。
可以再使用一个对音乐评分的例子来看一下隐特征矩阵的含义:
A喜欢带有小清新,吉他伴奏,王菲的歌曲,如果一首歌正好是王菲唱的,并且是吉他伴奏的小清新,那么就可以将这首歌推荐给这个用户,所以这里是三个标签🏷连接起了用户和歌曲。又每首歌中所包含的元素不尽相同,因此,我们可以去找如下两个矩阵
-
潜在因子——用户矩阵
小清新 重口味 优雅 伤感 五月天 三 0.6 0.8 0.1 0.1 四 0.1 0 0.9 0.1 五 0.5 0.7 0.9 0.9 -
潜在因子——音乐矩阵P
表示每种音乐中含有各种元素的成分,如下表中,音乐A是一个偏小清新的音乐,含有小清新的Latent Factor的成分是0.9,重口味的成分是0.1,优雅成分0.2小清新 重口味 优雅 伤感 五月天 乐A 0.9 0.1 0.2 0.4 乐B 0.5 0.6 0.1 0.9 乐C 0 0.6 0.1 0.2
那么有了以上矩阵,我们可以认为张三对音乐A的喜欢程度为
0.6∗0.9+0.8∗0.1+0.1∗0.2+0.1∗0.4+0.7∗0=0.690.6*0.9+0.8*0.1+0.1*0.2+0.1*0.4+0.7*0 = 0.690.6∗0.9+0.8∗0.1+0.1∗0.2+0.1∗0.4+0.7∗0=0.69
基于此,我们也可以得到一个用户——音乐评分的共现矩阵
音乐A | 音乐B | 音乐C | 音乐D | |
---|---|---|---|---|
张三 | 0.68 | 1.58 | 0.28 | 0.51 |
李四 | 0.31 | 0.43 | 0.47 | 0.11 |
王五 | 1.06 | 1.57 | 0.73 | 0.69 |
所以在此例子中,小清新,重口味,优雅这些就可以看作是隐含特征,而我们就可以用这些隐含特征来将用户的兴趣和音乐进行一个分类,其本质即为找到用户/音乐的一个隐向量表达形式,通过该隐向量就可以来进行用户/音乐之间相似度的判定。
但是在实际情况下,我们一般也是只能有最后的用户——物品打分矩阵,并且矩阵会存在很多缺失值如
音乐A | 音乐B | 音乐C | 音乐D | |
---|---|---|---|---|
张三 | 0.68 | ? | ? | 0.51 |
而对于使用UserCF或者ItemCF去填充也是很麻烦的,对此,我们可以使用[[矩阵分解]]
矩阵分解的原理
如果我们有用户——物品打分的共线矩阵YYY(存在缺失值),基于[[矩阵分解]]的原理,我们求出矩阵PPP和QQQ有:P×Q=YP \times Q = YP×Q=Y
其中,矩阵乘法将m×nm\times nm×n的共现矩阵Y分分解为m×km \times km×k的用户矩阵和k×nk \times nk×n的物品矩阵,其中m为用户的个数,n为物品的个数,而k为隐向量的维度即隐含特征的个数,但是这里的隐含特征变得无法解释,并不是和我们之前矩阵小清新的例子一样是明显可解释的,而对于k而言,k的大小决定了隐向量的表达能力的强弱,k越大,表达信息就越强,划分得就更具体。
在有了用户矩阵P和物品矩阵Q之后,如果我们想计算用户uuu对物品iii的评分,只需要
Preference(u,i)=rui=puTqi=∑f=1Fpu,kqk,iPreference(u, i) = r_{ui} = p^T_uq_i = \sum_{f=1}^Fp_{u,k}q_{k,i}Preference(u,i)=rui=puTqi=f=1∑Fpu,kqk,i
其中,pup_upu为用户uuu所对应的隐向量,qiq_iqi为用户iii所对应的隐向量
矩阵分解算法的求解
矩阵分解常用方法为[[特征值分解EVD]]与[[奇异值分解SVD]],但是这两种方法在这里并不适用,比如EVD要求分解的矩阵为方阵,但是对于用户——物品打分矩阵而言,不一定是方阵的形式,而对于SVD分解计算机复杂度非常高
Basic SVD
Funk-SVD:把求解上面两个矩阵的参数问题转换成一个最优化问题,可以通过训练集里面的观察值利用最小化来学习用户矩阵和物品矩阵
如果我们想计算用户uuu对物品iii的评分,可以使用Preference(u,i)=rui=puTqi=∑f=1Fpu,kqk,iPreference(u, i) = r_{ui} = p^T_uq_i = \sum_{f=1}^Fp_{u,k}q_{k,i}Preference(u,i)=rui=puTqi=f=1∑Fpu,kqk,i
而我们一般只会有ruir_{ui}rui的真实数据,并没有pup_upu和qiq_iqi,所以基于修正的思想,我们可以初始化puRqip_u^Rq_ipuRqi,然后计算出r^ui=puTqi\hat{r}_{ui} = p_u^Tq_ir^ui=puTqi,从而得到误差
eui=rui−r^uie_{ui} = r_{ui} - \hat{r}_{ui}eui=rui−r^ui
接着求出误差平方和
SSE=∑u,ieui2=∑u,i(rui−∑k=1Kpu,kqk,i)2SSE = \sum_{u, i}e_{ui}^2=\sum_{u, i}(r_{ui}-\sum_{k=1}^Kp_{u, k}q_{k, i})^2SSE=u,i∑eui2=u,i∑(rui−k=1∑Kpu,kqk,i)2
有了误差之后,我们可以利用误差进行修正从而使SSE降到最小,转化为一个最优化问题,而目标函数为
minq∗,p∗∑(u,i)∈K(rui−puTqi)2\min_{q^*, p^*}\sum_{(u, i) \in K}(r_{ui} - p_u^Tq_i)^2q∗,p∗min(u,i)∈K∑(rui−puTqi)2
接下来可以使用梯度下降去降低损失,有
pu,k=pu,k−η(−euiqk,i)=pu,k+ηeuiqk,ip_{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
qk,i=qk,i−η(−euipu,k)=qk,i+ηeuipu,kq_{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^ui=puTqi\hat{r}_{ui} = p^T_uq_ir^ui=puTqi只能评判一部分属性,对于一个评分系统而言,有些固有属性和用户物品无关,而用户也有有些属性和物品无关,物品也有些属性和用户无关,所以提出了另一种[[LFM]],在原有基础上添加了偏置项。
LFM
LFM在原有基础上加了偏置项,来消除用户和物品打分的偏差,即预测公式如下:
r^ui=μ+bu+bi+puT⋅qi\hat{r}_{ui} = \mu + b_u + b_i + p^T_u \cdot q_ir^ui=μ+bu+bi+puT⋅qi
加入了3个偏置项μ,bu,bi\mu, b_u, b_iμ,bu,bi
- μ\muμ:训练集中,也就是那个矩阵Y所有非空元素的平均值。因为可能在一个网站的评价打分中,因为网站的定位和销售物品不同,所以网站的整体打分分布会产生差异,所以μ\muμ可以表示网站本身对用户评分的影响。
- bub_ubu:用户偏差系数,是用户uuu所有打分的均值, 可以当作训练参数。这一项表示了用户的评分习惯中和物品没有关系的那种因素
- bib_ibi:物品偏差系数,是物品iii收到的所有评分的均值,可以当作训练参数。表示了物品接受的评分中和用户没有关系的因素
而此时添加了偏置系数之后,SSE的形式也需要改变,如果把bub_ubu和bib_ibi当作训练参数的话,那么它俩的更新公式为bu+=η(eui−λbu)b_u += \eta (e_{ui} - \lambda b_u)bu+=η(eui−λbu) bi+=η(eui−λbi)b_i += \eta(e_{ui} - \lambda b_i)bi+=η(eui−λbi),而对于pu,kp_{u,k}pu,k和pk,ip_{k,i}pk,i,导数没有变化,更新公式也没有变化。
实现例子的代码:
import numpy as np
import randomclass SVD():def __init__(self, rating_data, F=5, alpha=0.1, lmbda=0.1, max_iter=100):self.F = Fself.P = dict()self.Q = dict()self.rating_data = rating_dataself.bi = dict()self.bu = dict()self.mu = 0.0self.alpha = alphaself.lmbda = lmbdaself.max_iter = max_itercnt = 0for 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] = 0cnt += 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] = 0self.mu /= cntdef 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_uiself.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.1def 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.mudef 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 datarating_data = load_data()
basicsvd = SVD(rating_data, F=10)
basicsvd.train()
print(item, basicsvd.predict('A', 5))
FM模型
FM模型的引入
逻辑回归模型及其缺点
一般做CTR预估时最简单的思路即将特征做线性回归(逻辑回归LR),但这样本质上是一个线性模型,由于sigmoid函数是一个单调增函数不会改变里面的线性模型的CTR预测顺序,因此逻辑回归的效果会比较差,即LR的缺点有:
- 是一个线性模型
- 每个特征对最终输出结果独立,需要手动交叉特征(xi∗xjx_i * x_jxi∗xj)
[[二叉交叉项的考虑及改进]]
考虑到做特征交叉较为麻烦,于是考虑所有的二次交叉,于是将目标函数由原来的y=w0+∑i=1nwixiy = w_0 + \sum_{i=1}^nw_ix_iy=w0+i=1∑nwixi改为y=w0+∑i=1nwixi+∑in−1∑j=i+1nwi,jxixjy = w_0 + \sum_{i=1}^nw_ix_i+\sum_{i}^{n-1}\sum_{j=i+1}^nw_{i,j}x_ix_jy=w0+i=1∑nwixi+i∑n−1j=i+1∑nwi,jxixj
但是针对上式存在一个问题即只有当xix_ixi与xjx_jxj同时不为0时此二阶交叉项才能起作用
于是提出FM,而FM将上述式子改为y=w0+∑i=1nwixi+∑in−1∑j=i+1n<vi,vj>xixjy = w_0 + \sum_{i=1}^nw_ix_i+\sum_{i}^{n-1}\sum_{j=i+1}^n<v_i,v_j>x_ix_jy=w0+i=1∑nwixi+i∑n−1j=i+1∑n<vi,vj>xixj
此处的解释为,在这里是对每个xix_ixi计算一个embeddingembeddingembedding,接着将两个embeddingembeddingembedding计算内积即<vi,vj><v_i,v_j><vi,vj>来代替之前的wi,jw_{i,j}wi,j,好处是这个模型的泛化能力强,即使存在有两个特征从未在训练集中同时出现过,我们也可以计算出它们的wi,jw_{i,j}wi,j,我们只需要xix_ixi和其他的xkx_kxk同时在训练集中出现过则可计算出xix_ixi的EmbeddingEmbeddingEmbedding
FM公式的理解
对于FM公式而言,模型表达能力大于LR,只有当交叉项参数wijw_{ij}wij全为0的时候,才会退化为LR,而且后面的二阶交叉项的数量一共有1+2+3+⋯+n−1=n(n−1)21+2+3+\cdots + n-1 = \frac{n(n-1)}{2}1+2+3+⋯+n−1=2n(n−1),且任意两个参数之间是独立的。
def 任意一个实对称矩阵([[正定矩阵]])WWW都存在一个矩阵VVV,使得W=V⋅VTW = V \cdot V^TW=V⋅VT
y^(X)=w0+∑i=1nwixi+∑in−1∑j=i+1n<vi,vj>xixj\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_jy^(X)=w0+i=1∑nwixi+i∑n−1j=i+1∑n<vi,vj>xixj
其中,需要估计的参数有w0∈R,wi∈R,V∈R,<⋅,⋅>w_0 \in R, w_i \in R, V \in R, <\cdot, \cdot>w0∈R,wi∈R,V∈R,<⋅,⋅>是两个长度为k的向量的内积
对于FM模型而言,在[[二叉交叉项的考虑及改进]]中,我们提出了使用<⋅,⋅><\cdot,\cdot><⋅,⋅>来代替wijw_{ij}wij的改进,从而使二次项的参数数量减少为knknkn个,远远少于多项式模型的二项式参数,此外,参数因子化使得xhxix_hx_ixhxi与xixjx_ix_jxixj不再是独立的。
FM模型是一个通用的拟合模型,可以采用不同的损失函数用以解决regression,classification问题。
FM的理解:FM可以用于解决大型稀疏数据中的特征组合问题。对于MF而言,只存在两个两个特征信息,而FM可以将两个特征进行二阶交叉组合,形成一个高阶特征。具体可以参考推荐系统之FM与MF傻傻分不清楚。
MF其实算是FM的特例,只有两个特征的特例,给出一个矩阵来帮助理解,希望自己之后看到这个例子可以想起来
user1 user2 user3 item1 1 2 3 item2 2 3 4 item3 3 4 5 这个是MF的输入矩阵,而转化为FM的格式就变为
user1 user2 user3 item1 item2 item3 score 1 0 0 1 0 0 1 1 0 0 0 1 0 2 1 0 0 0 0 1 3 0 1 0 1 0 0 2 0 1 0 0 1 0 3 0 1 0 0 0 1 4 0 0 1 1 0 0 3 0 0 1 0 1 0 4 0 0 1 0 0 1 5