1、特征组合是许多机器学习建模过程中遇到的问题,如果对特征直接建模,很有可能会忽略掉特征与特征之间的关联信息,因此,可以通过构建新的交叉特征这一特征组合方式提高模型的效果。
2、高维的稀疏矩阵是实际工程中常见的问题,并直接会导致计算量过大,特征权值更新缓慢。试想一个10000*100的表,每一列都有8种元素,经过one-hot独热编码之后,会产生一个10000*800的表。因此表中每行元素只有100个值为1,700个值为0。
而FM的优势就在于对这两方面问题的处理。首先是特征组合,通过对两两特征组合,引入交叉项特征,提高模型得分;其次是高维灾难,通过引入隐向量(对参数矩阵进行矩阵分解),完成对特征的参数估计。
我们已经知道了FM可以解决特征组合以及高维稀疏矩阵问题,而实际业务场景中,电商、豆瓣等推荐系统的场景是使用最广的领域,打个比方,小王只在豆瓣上浏览过20部电影,而豆瓣上面有20000部电影,如果构建一个基于小王的电影矩阵,毫无疑问,里面将有199980个元素全为0。而类似于这样的问题就可以通过FM来解决。
在展示FM算法前,我们先回顾一下最常见的线性表达式:
其中w0为初始权值,或者理解为偏置项,wi为每个特征xi对应的权值。可以看到,这种线性表达式只描述了每个特征与输出的关系。
FM的表达式如下,可观察到,只是在线性表达式后面加入了新的交叉项特征及对应的权值。
FM表达式的求解核心在于对交叉项的求解。下面是很多人用来求解交叉项的展开式,对于第一次接触FM算法的人来说可能会有疑惑,不知道公式怎么展开的,接下来笔者会手动推导一遍。
设有3个变量(特征)x1x2x3,每一个特征的隐变量分别为v1=(123)、v2=(456)、v3=(121),即:
设交叉项所组成的权矩阵W为对称矩阵,之所以设为对称矩阵是因为对称矩阵有可以用向量乘以向量转置替代的性质。那么W=VVT,即
所以:
实际上,我们应该考虑的交叉项应该是排除自身组合的项,即对于x1x1、x2x2、x3x3不认为是交叉项,那么真正的交叉项为x1x2、x1x3、x2x1、x2x3、x3x1、x3x2。去重后,交叉项即x1x2、x1x3、x2x3。这也是公式中1/2出现的原因。
对交叉项有了基本了解后,下面将进行公式的分解,还是以n=3为例,
上面的例子是对3个特征做的交叉项推导,因此对具有n个特征,FM的交叉项公式就可推广为:
我们还可以进一步分解:
所以FM算法的交叉项最终可展开为:
假设训练数据集dataMatrix的shape为(20000,9),取其中一行数据作为一条样本i,那么样本i的shape为(1,9),同时假设隐向量vi的shape为(9,8)(注:8为自定义值,代表embeddingvector的长度)
所以5.3小节中的交叉项可以表示为:
sum((inter_1)^2-(inter_2)^2)/2
其中:
inter_1=i*vshape为(1,8)
inter_2=np.multiply(i)*np.multiply(v)shape为(1,8)
可以看到,样本i经过交叉项中的计算后,得到向量shape为(1,8)的inter_1和inter_2。
由于维度变低,所以此计算过程可以近似认为在交叉项中对样本i进行了embeddingvector转换。
故,我们需要对之前的理解进行修正:
具体可以结合第7节点的代码实现进行理解。
利用梯度下降法,通过求损失函数对特征(输入项)的导数计算出梯度,从而更新权值。设m为样本个数,θ为权值。
如果是回归问题,损失函数一般是均方误差(MSE):
所以回归问题的损失函数对权值的梯度(导数)为:
如果是二分类问题,损失函数一般是logitloss:
所以分类问题的损失函数对权值的梯度(导数)为:
相应的,对于常数项、一次项、交叉项的导数分别为:
FM算法的Python实现流程图如下:
我们需要注意以下四点:
1.初始化参数,包括对偏置项权值w0、一次项权值w以及交叉项辅助向量的初始化;
2.定义FM算法;
3.损失函数梯度的定义;
4.利用梯度下降更新参数。
下面的代码片段是以上四点的描述,其中的loss并不是二分类的损失loss,而是分类loss的梯度中的一部分:
loss=self.sigmoid(classLabels[x]*p[0,0])-1
实际上,二分类的损失loss的梯度可以表示为:
gradient=(self.sigmoid(classLabels[x]*p[0,0])-1)*classLabels[x]*p_derivative
其中p_derivative代表常数项、一次项、交叉项的导数(详见本文第6小节)。