推荐算法之FM(因子分解机)模型,召回与排序的利器
在这篇文章我们将介绍因式分解机模型(FM),为行文方便后文均以FM表示。FM模型结合了支持向量机与因子分解模型的优点,并且能够用了回归、二分类以及排序任务,速度快,是推荐算法中召回与排序的利器。FM算法和前面我们介绍的LFM模型模型都是基于矩阵分解的推荐算法,但在大型稀疏性数据中FM模型效果也不错。本文首先将阐述FM模型原理,然后针对MovieLens数据集将FM算法用于推荐系统中的ranking阶段,给出示例代码。最后,我们将对该算法进行一个总结。
1. FM算法
FM是一个如SVM一样通用的预测器,并且能够在数据非常稀疏的情况下估算训练出可靠的参数。同时,FM不仅能够利用一阶特征,通过分解参数也能够利用二阶乃至更高阶特征,并且速度相对其它算法更快更可靠。在本章我将介绍FM原理并详细讨论模型方程,然后简短说明如何将之用于多个预测任务。
1.1 FM模型
当d=2,即我们最高阶只关注到二阶交互特征时,FM的模型方程式定义如下:
\[
(1)\hat{y} := w_0 + \sum_{i=1}^{n}{w_ix_i}+\sum_{i=1}^{n}\sum_{j=i+1}^{n}<v_i,v_j>x_jx_j
\]
在这里,模型参数的估计空间为:
\[
w_0\in R, w\in R^n, V \in R^{n*k}
\]
并且,<·,·>表示两个大小为k的向量的点积:
\[
<v_i, v_j> :=\sum_{f=1}^{k}{v_{i,f}·v_{j,f}}
\]
在V中\(v_i\)描述了第i个特征,\(k\in N_0^+\)是一个定义模型分解维度的超参数。
2-way FM(degree=2)模型能够捕获所有的一阶特征与二阶交互特征:
- \(w_0\)是一个全局偏置向量
- \(w_i\)对第i个变量(特征)进行建模
- \(w_{ij}\)对第i个变量(特征)与第j个变量(特征)之间的交互作用进行了建模。在这里,FM并非定义出\(w_{ij} \in R\) ,而是通过分解参数W对交互建模。这也是FM在稀疏情况下能进行高质量参数估计的关键点。
看到这里可能会有一个疑问,FM是如何通过分解参数对交互建模的呢?
众所周知,在当\(k\)足够大的时候,任何一个正定矩阵\(W\)都能存在一个向量\(V\)使得\(W=VV^t\)。这表明,如果选择的\(k\)足够大则FM可以表示任何交互矩阵。然而,在数据十分稀疏的情况下,\(k\)只需要取一个较小的值就行,这是因为没有足够的数据来估计复杂的交互矩阵\(W\),并且限制\(k\)的大小反而还能提高模型的泛化性能。
1.2 稀疏数据下的参数估计
在数据十分稀疏的情况下,通常没有充足的数据直接估计变量之间的交互参数\(w_{ij}\)。FM模型在这种场景下能够直接估计变量之间的交互是因为其通过分解交互参数来破坏参数\(w_{ij}\)的独立性,从而间接的达到训练参数的目的。这意味着一个交互数据也有助于估计相关交互的参数。为了让读者理解清晰,我们将通过一个栗子来阐述:
假设我们拥有电影评分系统的评分数据。系统记录了某个时间\(t \in R\)某个用户\(u \in U\)为电影\(i \in I\)评分 \(r\in {1, 2, 3, 4, 5}\).
U = {A, B, C}
I = {TI, NH, SW, ST}
观察到数据形式为:
S = {(A, TI, 2010-1, 5), (A, NH, 2010-2, 3), (A, SW, 2010-4, 1), (B, SW, 2009-5, 4), (B, ST,2009-8,5), (C, TI, 2009-9, 1), (C, SW, 2009-12,5)}
在这里,假设我们要估计A和ST组合下的评分y,显然训练数据中不存在变量\(x_A\)和变量\(x_{ST}\)都不为零的数据\(x\),因此直接估计交互参数\(w_{A,ST}\)没有任何作用(\(w_{A,ST}=0\))。但是通过分解交互参数\(w_{A,ST}\)为\(<v_{A},v_{ST}>\)我们就可以估计出该交互参数值。这是因为用户A对别的电影的评分能够帮助估计到参数\(V_A\),而别的用户对ST的评分也能帮助估计参数\(V_{ST}\)。
1.3 公式演算
如方程(1)所示,其时间复杂度为\(O(kn^2)\),但通过重新演算可将其时间复杂度降低到线性。如下所示:
\[
(2)\sum_{i=1}^{n}\sum_{j=i+1}^{n}<v_i,v_j>x_jx_j=\frac{1}{2}\sum_{f=1}{k}\left( \left(\sum_{i=1}^{n}{v_{i,f}x_i}\right)^2 - \sum_{i=1}^{n}{v_{i,f}^2x_i^2} \right)
\]
该等式的时间复杂度与k,n线性相关,为\(O(kn)\)
2. FM用于ranking
在本节,我将针对MovieLens数据集(ml-100k)走完推荐系统的数据预处理、召回、排序阶段并作介绍。其中FM用于ranking阶段。
2.1 数据预处理及召回策略
如图所示,将用户与电影使用one-hot编码,同时提取历史评分矩阵,用户职业进行one-hot编码,性别也是。召回阶段,简单粗暴的基于规则进行匹配item,具体详见github。
2.2 ranking阶段
实现FM模型,通过FM模型训练参数得到召回数据中用户对召回物品的评分并进行排序。算法实现代码如下。
# 定义FM模型
class FM_model(torch.nn.Module):
"""FM Model"""
def __init__(self, n, k):
super(FM_model, self).__init__()
self.n = n
self.k = k
self.linear = torch.nn.Linear(self.n, 1, bias=True)
self.v = torch.nn.Parameter(torch.rand(self.n, self.k))
def fm_layer(self, x):
# w_i * x_i 线性部分
linear_part = self.linear(x)
print(linear_part.shape)
# pairwise interactions part 1
inter_part1 = torch.mm(x, self.v)
# pairwise interactions part 2
inter_part2 = torch.mm(torch.pow(x, 2), torch.pow(self.v, 2))
inter_part = 0.5 * torch.sum(torch.sub(torch.pow(inter_part1, 2), inter_part2), dim=1).reshape(-1, 1)
output = linear_part + inter_part
return output
def forward(self, x):
output = self.fm_layer(x)
return output
详细代码,请前往github查看FM算法实现
3.小结
在本文中,我们介绍了FM模型。FM将SVM的通用性和因式分解模型的优势结合在一起。与SVM相比,FM能够在数据极其稀疏的情况下估计模型参数,并且时间复杂度与分解维数k和特征量n线性相关,速度较快,是推荐系统中召回与排序的利器。为了方便大家学习,作者特意针对MovieLens数据集走了一遍预处理、召回、排序的流程,希望能够帮助大家理解该算法,理解推荐系统。
PS:(◠◡◠)觉得作者文章还不错的话,请点一下推荐哦!万分感谢!)
原文地址:https://www.cnblogs.com/rainbowly/p/12324128.html
- 那些年我们用Java写过的小游戏 --- 快速击键系统
- 那些年我们的(具有含金量)MySQL测试题目
- Java 异常处理之 论 finally块何时候不走
- Java 中的异常处理机制
- Java 关于接口的那点事儿
- 论 Java 中的内存分配
- Javascript基础回顾 之(一) 类型
- Javascript基础回顾 之(三) 面向对象
- Javascript基础回顾 之(二) 作用域
- 一不小心写了个WEB服务器
- 遍历算法(1)
- Membership三步曲之入门篇 - Membership基础示例
- Java-String.intern的深入研究
- 从Membership 到 .NET4.5 之 ASP.NET Identity
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Jmeter 常用函数(24)- 详解 __digest
- you-dont-know-websocket
- Cent os 7之KVM虚拟化基础管理
- 常用 Maven 命令介绍
- Linux下diff命令用法详解
- 详解Numpy中的数组拼接、合并操作
- 批量更改图像尺寸到统一大小
- 张东升,我知道是你!如何使用GAN做一个秃头生产器
- Roslyn 在 NuGet 包中放注释 xml 文件的方法
- OpenCV3 图像的加载、修改、显示与保存
- 打卡群刷题总结0727——搜索旋转排序数组 II
- dotnet 的 TaskCompletionSource 的 TrySetResult 是线程安全
- OpenCV 摄像头与视频读取并显示
- OpenCV 边缘检测
- Spring Boot 集成 WebSocket 实现服务端推送消息到客户端