推荐系统概述(一)
推荐系统是一种信息过滤系统,用于预测用户对物品的评分或偏好。解决的是信息过载和长尾问题(长尾理论)。它的本质是通过一定的方式将用户和物品联系起来。
推荐系统在为用户推荐物品时通常有两种方式:
1.评分预测
2.TopN推荐
主流的推荐系统算法可以分为协同过滤推荐(Collaborative Filtering Recommendation)、基于内容推荐(Content-basedRecommendation)和混合推荐等。
协同过滤
仅仅基于用户行为数据设计的推荐算法一般称为协同过滤算法。
主要包括基于邻域的方法(neighborhood-based)、 隐语义模型(latent factor model)、 基于图的随机游走算法(random walk on graph)等。而基于邻域的方法主要包含基于用户的协同过滤算法和基于物品的协同过滤算法。
1)基于用户的协同过滤算法
基于用户的协同过滤算法主要包括两个步骤。
(1) 找到和目标用户兴趣相似的用户集合。
(2) 找到这个集合中的用户喜欢的,且目标用户没有听说过的物品推荐给目标用户
步骤(1)的关键就是计算两个用户的兴趣相似度。可以通过Jaccard(杰卡德)公式或者通过余弦相似度计算
Jaccard(杰卡德)公式:
$$
W(u,v) = \frac{N(u) \bigcap N(v)}{N(u) \bigcup N(v)}
$$
余弦相似度:
$$
W(u,v) = \frac{N(u) \bigcap N(v)} {\sqrt{|N(u)| |N(v)|}}
$$
2)基于物品的协同过滤算法
基于物品的协同过滤(item-based collaborative filtering)算法是目前业界应用最多的算法。基于物品的协同过滤算法主要分为两步。
(1) 计算物品之间的相似度。
(2) 根据物品的相似度和用户的历史行为给用户生成推荐列表
$$
w(i,j) = \frac{N(i) \bigcap N(j)} {\sqrt{|N(i)| |N(j)|}}
$$
- 改进
协同过滤可能会带来马太效应,所以会有一些常见的改进方法。
基于用户的协同过滤主要改进在用户对物品的喜好程度上,比如惩罚对热门物品的喜好程度,增加喜好程度的时间衰减等方法;
基于物品的改进主要有物品中心化和用户中心化,即先分别减去物品、用户分数的均值,再进行相似度计算。
UserCF和ItemCF的综合比较
UserCF的推荐结果着重于反映和用户兴趣相似的小群体的热点,而ItemCF的推荐结果着重于维系用户的历史兴趣。换句话说, UserCF的推荐更社会化,反映了用户所在的小型兴趣群体中物品的热门程度,而ItemCF的推荐更加个性化,反映了用户自己的兴趣传承。
例如,UserCF适合用于新闻推荐;ItemCF适合用于图书、电子商务和电影网站。
3)隐语义模型
核心思想是通过隐含特征(latent factor)联系用户兴趣和物品,找出潜在的主题和分类。LFM(latent factor model)通过如下公式计算用户u对物品i的兴趣:
$$
Preference(u,i) = r_{ui} = {p_u}^T q_i = \sum_{f=1}^F p_{u,k} q_{i,k}
$$
定义P矩阵是user-class矩阵,矩阵值$P_{ij}$表示的是user i对class j的兴趣度;Q矩阵式class-item矩阵,矩阵值Qij表示的是item j在class i中的权重,权重越高越能作为该类的代表。那么,用户U对物品I的兴趣度为:
$$
R_{UI} = P_U Q_I = \sum_{k=1}^K P_{U,K} Q_{K,I}
$$
使用LFM后,我们不需要关心分类的角度,结果都是基于用户行为统计自动聚类的;不需要关心分类粒度的问题,通过设置LFM的最终分类数就可控制粒度,分类数越大,粒度约细
在user-item集K={(U,I)},其中如果(U,I)是正样本,则RUI=1,否则RUI=0。损失函数如下所示:
$$
C = \sum (r_{u,i}-\hat{r_{u,i}})^2 = \sum (r_{u,i}-\sum_{k=1}^K p_{u,k} q_{k,i})^2+\lambda ||p_u||^2 + \lambda ||q_i||^2
$$
对$p_{u,k}$,$q_{k,i})$分别求偏导数,根据随机梯度下降法,将参数沿着最速下降方向向前推进
- 优缺点
优点:
- LFM具有比较好的理论基础
- LFM大量节省了训练过程中的内存
缺点:
- 很难实现实时的推荐。经典的LFM模型每次训练时都需要扫描所有的用户行为记录,这样才能计算出用户隐类向量和物品隐类向量。而且LFM的训练需要在用户行为记录上反复迭代才能获得比较好的性能;
- LFM无法提供很好的推荐解释
4)基于随机游走的PersonalRank算法
将用户行为表示为二分图模型。假设给用户u进行个性化推荐,要计算所有节点相对于用户u的相关度,则PersonalRank从用户u对应的节点开始游走,每到一个节点都以1-d的概率停止游走并从u重新开始,或者以d的概率继续游走,从当前节点指向的节点中按照均匀分布随机选择一个节点往下游走。这样经过很多轮游走之后,每个顶点被访问到的概率也会收敛趋于稳定,这个时候我们就可以用概率来进行排名了。
在执行算法之前,我们需要初始化每个节点的初始概率值。如果我们对用户u进行推荐,则令u对应的节点的初始访问概率为1,其他节点的初始访问概率为0,然后再使用迭代公式计算。
$$
PR(i)=(1-d)r_i+d\sum_{j \in in(i)} \frac {PR(j)}{|out(i)|} \\
r_i =
\begin{cases}
1 \ \ i=u \\
0 \ \ i!=u
\end{cases}
$$
算法优化方法:
(1)三分图(user,tag,item)
(2)转移矩阵算法,降低时间复杂度
矩阵化实现:
$$
r = (1-\alpha)r_o + \alpha M^T r
$$
其中,r是m+n行,1列的矩阵,每一行代表该顶点对固定顶点的PR值;是m+n行,1列的矩阵,负责选取某一个顶点作为固定顶点,其数值只有1行为1,其余为0。M是m+n行,m+n列的矩阵,是转移矩阵,其值$M_{ij}=\frac{1}{out(i)},j \in out(i) \ else \ 0$,即为顶点的出度倒数,若没有连接边则为0。上式可转换为:
$$
r = (E-\alpha M^T)^{-1}(1-\alpha)r_o
$$
其中,$(E-\alpha M^T)^{-1}$可以看做所有顶点的推荐结果,每一列代表一个顶点项,对该顶点的PR值。
- 特点:
- 主题无关性
- 对新物品不利
5)Slope One算法
Slope One 算法 是一种基于评分的预测算法, 本质上也是一种基于项目的算法。与一般的基于项目的算法不同, 该算法不计算项目之间的相似度, 而是用一种简单的线性回归模型进行预测(可以扩展) 算法易于实现, 计算速度快, 可扩展性好, 同时对数据稀疏性有较好的适应性。
主要两步:
Step1:计算物品之间的评分差的均值,记为物品间的评分偏差(两物品同时被评分);
Step2:根据物品间的评分偏差和用户的历史评分,预测用户对未评分的物品的评分。
该算法适用于物品更新不频繁,数量相对较稳定并且物品数目明显小于用户数的场景。依赖用户的用户行为日志和物品偏好的相关内容。
- 优缺点
优点:
- 算法简单,易于实现,执行效率高;
- 可以发现用户潜在的兴趣爱好;
缺点:
- 依赖用户行为,存在冷启动问题和稀疏性问题。
协同过滤算法优缺点:
- 协同过滤算法只是使用“用户”和“物品”两个变量,并且只是根据相似性这个变量计算,是基于统计的低阶推荐算法,不具有精准推荐
- 对于新物品的曝光,协同过滤效果很差
内容推荐
它的思想非常简单:根据用户过去喜欢的物品(本文统称为 item),为用户推荐和他过去喜欢的物品相似的物品。而关键就在于这里的物品相似性的度量,这才是算法运用过程中的核心。
CB的过程一般包括以下三步:
物品表示(Item Representation):为每个item抽取出一些特征(也就是item的content了)来表示此item;
特征学习(Profile Learning):利用一个用户过去喜欢(及不喜欢)的item的特征数据,来学习出此用户的喜好特征(profile);
生成推荐列表(Recommendation Generation):通过比较上一步得到的用户profile与候选item的特征,为此用户推荐一组相关性最大的item。
CB的优点:
- 用户之间的独立性(User Independence):既然每个用户的profile都是依据他本身对item的喜好获得的,自然就与他人的行为无关。而CF刚好相反,CF需要利用很多其他人的数据。CB的这种用户独立性带来的一个显著好处是别人不管对item如何作弊(比如利用多个账号把某个产品的排名刷上去)都不会影响到自己。
- 好的可解释性(Transparency):如果需要向用户解释为什么推荐了这些产品给他,你只要告诉他这些产品有某某属性,这些属性跟你的品味很匹配等等。
- 新的item可以立刻得到推荐(New Item Problem):只要一个新item加进item库,它就马上可以被推荐,被推荐的机会和老的item是一致的。而CF对于新item就很无奈,只有当此新item被某些用户喜欢过(或打过分),它才可能被推荐给其他用户。所以,如果一个纯CF的推荐系统,新加进来的item就永远不会被推荐:( 。
CB的缺点: - item的特征抽取一般很难(Limited Content Analysis):如果系统中的item是文档(如个性化阅读中),那么我们现在可以比较容易地使用信息检索里的方法来“比较精确地”抽取出item的特征。但很多情况下我们很难从item中抽取出准确刻画item的特征,比如电影推荐中item是电影,社会化网络推荐中item是人,这些item属性都不好抽。其实,几乎在所有实际情况中我们抽取的item特征都仅能代表item的一些方面,不可能代表item的所有方面。这样带来的一个问题就是可能从两个item抽取出来的特征完全相同,这种情况下CB就完全无法区分这两个item了。比如如果只能从电影里抽取出演员、导演,那么两部有相同演员和导演的电影对于CB来说就完全不可区分了。
- 无法挖掘出用户的潜在兴趣(Over-specialization):既然CB的推荐只依赖于用户过去对某些item的喜好,它产生的推荐也都会和用户过去喜欢的item相似。如果一个人以前只看与推荐有关的文章,那CB只会给他推荐更多与推荐相关的文章,它不会知道用户可能还喜欢数码。
- 无法为新用户产生推荐(New User Problem):新用户没有喜好历史,自然无法获得他的profile,所以也就无法为他产生推荐了。当然,这个问题CF也有。
矩阵分解
矩阵分解乃是实现隐语义模型的基石。
矩阵分解根据用户对物品的评分, 推断出用户和物品的隐语义向量, 然后根据用户和物品的隐语义向量来进行推荐。
推荐系统用到的数据可以有显式评分和隐式评分. 显式评分时用户对物品的打分, 显式评分矩阵通常非常稀疏. 隐式评分是指用户的浏览, 购买, 搜索等历史记录, 表示的是用户行为的有无, 所以是一个密集矩阵。
矩阵分解也有FunkSVD,BiasSVD,SVD++等常用形式,三种形式的差别就是在不同的预置Bias做了不同考虑
1)传统的奇异值分解SVD
奇异值分解(SVD)原理与主要应用在数据降维中,可以将这个用户物品对应的m×n矩阵M进行SVD分解,并通过选择部分较大的一些奇异值来同时进行降维
API:
sklearn.decomposition. import TruncatedSVD
问题:
1.基于稠密向量分解,稀疏向量无法计算
2.O(n^3)的计算计算复杂度,计算复杂,智能用在简单数据降维,不可用在大数据推荐
2)FunkSVD推荐算法/LFM算法
ALS是交替最小二乘的简称,在机器学习上下文中,ALS特指使用交替最小二乘求解的一个协同过滤推荐算法。它通过观察到的所有用户给物品的打分,来推断每个用户的喜好并向用户推荐合适的物品。例如:将用户(user)对商品(item)的评分矩阵分解为两个矩阵:一个是用户对商品隐含特征的偏好矩阵,另一个是商品所包含的隐含特征的矩阵。在这个矩阵分解的过程中,评分缺失项得到了填充,也就是说我们可以基于这个填充的评分来给用户最商品推荐了。
API:pyspark.mllib.recommendation import ALS
说明:
1,利用了梯度下降求解,考虑了正则化过拟合
2.没解决样本偏差
3)BiasSVD推荐算法:
在LFM中提到的$\hat{r_{u,i}}$中加入偏置项,即得到SVD模型。
$$
\hat{r_{u,i}}=\sum_{k=1}^K p_{u,k}q_{k,i} + \mu +b_u +b_i
$$
其中$\mu$表示训练集中物品的所有评分的平均值,$b_u$是用户偏置项,表示一个用户评分的平均值,$b_i$是物品偏置项,表示一个物品被评分的平均值。偏置项是固有属性,每个用户和物品都有自己的值,代表该物品被大众喜爱程度或某个用户对物品的苛刻程度。
新的代价函数为:
$$
C = \sum (r_{u,i}-\hat{r_{u,i}})^2 = \sum (r_{u,i}-\sum_{k=1}^K p_{u,k} q_{k,i})^2+\lambda ||b_u||^2 + \lambda ||b_i||^2
$$
通过随机梯度下降,可以得到
$$
\frac{\partial C}{\partial b_u} = r_{u,i} - \hat{r{u,i}} -\lambda b_u \\
\frac{\partial C}{\partial b_i} = r_{u,i} - \hat{r{u,i}} -\lambda b_i
$$
说明:
1,利用了梯度下降求解,正在了正则化,增加了偏置项
2,没有解决反馈回执
4)SVD++
SVD++算法就是在BiasSVD算法上进一步做优化,增加考虑用户的隐式反馈。
我们从上一步的BiasLFM(即SVD)继续演化就可以得到SVD++。SVD++在前面的基础上增加了隐式反馈和用户属性等基本信息,在学习的过程中又多了两个向量:隐式反馈的物品向量,用户属性的特征向量。
假设某个用户对某个物品进行了评分,这样的行为事实上蕴含了一定的信息,从侧面反映了用户的喜好,可以将这样的反映通过隐式参数的形式体现在模型中,从而得到一个更为精细的模型
$$
\hat{r_{u,i}}=\mu +b_u +b_i+q_i^T(p_u+|I_u|^{-\frac{1}{2}} \sum_{j \in I_u}y_j)
$$
其中$I_u$是该用户评价过的所有物品的集合,$y_j$是隐藏的评价了物品j反映出的个人喜好偏置。收缩因子取集合大小的根号是一个经验公式,并没有理论依据。
说明:
1,利用了梯度下降求解,正在了正则化,增加了偏置项,增加了反馈回执
2,没有解决时间序列的额权重衰减
5)Time SVD++
TIME SVD ++: 添加了时间动态
时间序列这个会引起两个状态变化:
①:物品的流行度或者是随时间的变化程度,原则大部分是会随时间衰减的,因为人的审美随时间变化,当然,没有随时间变化的那部分我们都称呼为“经典款”
②:人的评分标准也是随时间变化的,比如年轻时要求更严格,中年会更随和,年老会更和蔼。
③:同一天的人的审美变化应该不会有太大变化,有变化也是轻微的变化。
说明:
1,利用了梯度下降求解,正在了正则化,增加了偏置项,增加了反馈回执
2,解决了时间序列的额权重衰减
矩阵分解优劣势
主要的优势如下:
- 比较容易编程实现,随机梯度下降方法依次迭代即可训练出模型。
- 预测的精度比较高,预测准确率要高于基于领域的协同过滤以及基于内容CBR等方法。
- 比较低的时间和空间复杂度,高维矩阵映射为两个低维矩阵节省了存储空间,训练过程比较费时,但是可以离线完成;评分预测一般在线计算,直接使用离线训练得到的参数,可以实时推荐。
- 非常好的扩展性,如由SVD拓展而来的SVD++和 TIME SVD++。
矩阵分解的不足主要有:
- 训练模型较为费时。
- 推荐结果不具有很好的可解释性,无法用现实概念给分解出来的用户和物品矩阵的每个维度命名,只能理解为潜在语义空间。
关联规则
关联分析又称关联挖掘,就是在交易数据、关系数据或其他信息载体中,查找存在于项目集合或对象集合之间的频繁模式、关联、相关性或因果结构。或者说,关联分析是发现交易数据库中不同商品(项)之间的联系。关联分析的一个典型例子是购物篮分析。该过程通过发现顾客放人其购物篮中的不同商品之间的联系,分析顾客的购买习惯。通过了解哪些商品频繁地被顾客同时购买,这种关联的发现可以帮助零售商制定营销策略。其他的应用还包括价目表设计、商品促销、商品的排放和基于购买模式的顾客划分。
常用的关联规则算法有Apripri、FP-Tree算法,这样的算法也是基于统计模型的。同样使用“支持度”的指标做依据,只不过后者建立了项目表和权重书模型来处理,加速了扫描判别的磁盘IO。
常用的频繁项集的评估标准有支持度,置信度和提升度三个
- 支持度:几个关联的数据在数据集中出现的次数占总数据集的比重
$$
support(X=>Y) = \frac{\sigma(X \bigcap Y)}{N}
$$ - 置信度:一个数据出现后,另一个数据出现的概率,或者说数据的条件概率。
$$
confidence(X=>Y) = \frac{\sigma(X \bigcap Y)}{\sigma(X)}
$$ - 提升度:表示含有Y的条件下,同时含有X的概率,与X总体发生的概率之比
$$
lift(X=>Y) = \frac{confidence(X=>Y)}{P(Y)}
$$
1)Apriori算法
该算法主要包含两个步骤:首先找出数据集中所有的频繁项集,这些项集出现的频繁性要大于或等于最小支持度;然后根据频繁项集产生强关联规则,这些规则必须满足最小支持度和最小置信度。
算法原理:
如果一个项集是频繁项集,则它的所有子集都是频繁项集
如果一个集合不是频繁项集,则它的所有父集(超集)都不是频繁项集
关联分析的目标:
发现频繁项集:发现满足最小支持度的所有项集
发现关联规则:从频繁项集中提取所有高置信度的规则
Apriori算法采用了迭代的方法
1.先搜索出候选1项集及对应的支持度,剪枝去掉低于支持度的1项集,得到频繁1项集。
2.对剩下的频繁1项集进行连接,得到候选的频繁2项集,筛选去掉低于支持度的候选频繁2项集,得到真正的频繁二项集,
3.以此类推,迭代下去,直到无法找到频繁k+1项集为止,对应的频繁k项集的集合即为算法的输出结果
2)FP-growth算法
在FP-growth算法中,通过两次扫描事务数据库,把每个事务所包含的频繁项目按其支持度降序压缩存储到FP—tree中。在以后发现频繁模式的过程中,不需要再扫描事务数据库,而仅在FP-Tree中进行查找即可,并通过递归调用FP-growth的方法来直接产生频繁模式,因此在整个发现过程中也不需产生候选模式。该算法克服了Apriori算法中存在的问颢.在执行效率上也明显好于Apriori算法。
FP-growth算法通过构建FP-tree来压缩事务数据库中的信息,从而更加有效地产生频繁项集。FP-tree其实是一棵前缀树,按支持度降序排列,支持度越高的频繁项离根节点越近,从而使得更多的频繁项可以共享前缀。
基于深度学习的召回算法
1)item2vec
item2vec将用户的行为序列转化成item组成的句子,模仿word2vec训练word embedding将item embedding。基本思想是把原来高维稀疏的表示方式(one_hot)映射到低维稠密的向量空间中,这样我们就可以用这个低维向量来表示该项目(电影),进而通过计算两个低维向量之间的相似度来衡量两个项目之间的相似性。
embedding就是用一个低维的向量表示一个物体,可以是一个词,或是一个商品,或是一个电影等等。这个embedding向量的性质是能使距离相近的向量对应的物体有相近的含义
类似于Word2vec,item2vec有两种方式:CBOW和skip-gram模型。
CBOW使用的是词袋模型,模型的训练输入是某一个特征词的上下文相关的词对应的词向量,而输出就是这特定的一个词的词向量。
Skip-Gram模型和CBOW的思路是反着来的,即输入是特定的一个词的词向量,而输出是特定词对应的上下文词向量。
word2vec有两种改进方法,一种是基于Hierarchical Softmax的,另一种是基于Negative Sampling的。
首先,对于从输入层到隐藏层的映射,没有采取神经网络的线性变换加激活函数的方法,而是采用简单的对所有输入词向量求和并取平均的方法。
第二个改进就是从隐藏层到输出的softmax层这里的计算量个改进。为了避免要计算所有词的softmax概率,word2vec采样了霍夫曼树来代替从隐藏层到输出softmax层的映射。
由于我们把之前所有都要计算的从输出softmax层的概率计算变成了一颗二叉霍夫曼树,那么我们的softmax概率计算只需要沿着树形结构进行就可以了。
和之前的神经网络语言模型相比,我们的霍夫曼树的所有内部节点就类似之前神经网络隐藏层的神经元,其中,根节点的词向量对应我们的投影后的词向量,而所有叶子节点就类似于之前神经网络softmax输出层的神经元,叶子节点的个数就是词汇表的大小。在霍夫曼树中,隐藏层到输出层的softmax映射不是一下子完成的,而是沿着霍夫曼树一步步完成的,因此这种softmax取名为”Hierarchical Softmax”。
如何“沿着霍夫曼树一步步完成”呢?在word2vec中,我们采用了二元逻辑回归的方法,即规定沿着左子树走,那么就是负类(霍夫曼树编码1),沿着右子树走,那么就是正类(霍夫曼树编码0)。判别正类和负类的方法是使用sigmoid函数
关于嵌入维度数量(New Embedding维度)的一般经验法则:embedding_dimensions = number_of_categories**0.25
- 优缺点
缺点:
- 用户的行为序列时序性缺失
- 用户行为序列中的item强度是无区分性的
Item2Vec算法主流程
- 从log中抽取用户行为序列
- 将行为序列当成预料训练word2Vec得到item embedding
- 得到item sim关系用于推荐