搜广推校招面经二十八
美团推荐算法
一、介绍FM提取值的公式
1.1. FM 的基本形式
FM 的预测值可以表示为:
y
^
(
x
)
=
w
0
+
∑
i
=
1
n
w
i
x
i
+
∑
i
=
1
n
∑
j
=
i
+
1
n
⟨
v
i
,
v
j
⟩
x
i
x
j
\hat{y}(\mathbf{x}) = w_0 + \sum_{i=1}^n w_i x_i + \sum_{i=1}^n \sum_{j=i+1}^n \langle \mathbf{v}_i, \mathbf{v}_j \rangle x_i x_j
y^(x)=w0+i=1∑nwixi+i=1∑nj=i+1∑n⟨vi,vj⟩xixj
其中:
- y ^ ( x ) \hat{y}(\mathbf{x}) y^(x):模型的预测值;
- w 0 w_0 w0:全局偏置项;
- w i w_i wi:第 i i i 个特征的线性权重;
- x i x_i xi:第 i i i 个特征的值;
- v i \mathbf{v}_i vi:第 i i i 个特征的隐向量(长度为 k k k 的低维向量):隐向量用于将高维稀疏特征,降为低维稠密的特征。
- ⟨ v i , v j ⟩ \langle \mathbf{v}_i, \mathbf{v}_j \rangle ⟨vi,vj⟩:隐向量 v i \mathbf{v}_i vi 和 v j \mathbf{v}_j vj 的内积,用于建模特征 i i i 和 j j j 的交互关系。
1.2. 特征交互项的优化公式
直接计算二重求和
∑
i
=
1
n
∑
j
=
i
+
1
n
⟨
v
i
,
v
j
⟩
x
i
x
j
\sum_{i=1}^n \sum_{j=i+1}^n \langle \mathbf{v}_i, \mathbf{v}_j \rangle x_i x_j
∑i=1n∑j=i+1n⟨vi,vj⟩xixj 的时间复杂度为
O
(
n
2
k
)
O(n^2k)
O(n2k),在高维稀疏数据中效率较低。因此,FM 提出了一个优化公式,将复杂度降低到
O
(
k
n
)
O(kn)
O(kn)。
优化后的公式为:
∑
i
=
1
n
∑
j
=
i
+
1
n
⟨
v
i
,
v
j
⟩
x
i
x
j
=
1
2
∑
f
=
1
k
(
(
∑
i
=
1
n
v
i
,
f
x
i
)
2
−
∑
i
=
1
n
v
i
,
f
2
x
i
2
)
\sum_{i=1}^n \sum_{j=i+1}^n \langle \mathbf{v}_i, \mathbf{v}_j \rangle x_i x_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}^2 x_i^2 \right)
i=1∑nj=i+1∑n⟨vi,vj⟩xixj=21f=1∑k
(i=1∑nvi,fxi)2−i=1∑nvi,f2xi2
公式推导:
-
展开隐向量内积 ⟨ v i , v j ⟩ \langle \mathbf{v}_i, \mathbf{v}_j \rangle ⟨vi,vj⟩:
⟨ v i , v j ⟩ = ∑ f = 1 k v i , f v j , f \langle \mathbf{v}_i, \mathbf{v}_j \rangle = \sum_{f=1}^k v_{i,f} v_{j,f} ⟨vi,vj⟩=f=1∑kvi,fvj,f
因此:
∑ i = 1 n ∑ j = i + 1 n ⟨ v i , v j ⟩ x i x j = ∑ f = 1 k ∑ i = 1 n ∑ j = i + 1 n v i , f v j , f x i x j \sum_{i=1}^n \sum_{j=i+1}^n \langle \mathbf{v}_i, \mathbf{v}_j \rangle x_i x_j = \sum_{f=1}^k \sum_{i=1}^n \sum_{j=i+1}^n v_{i,f} v_{j,f} x_i x_j i=1∑nj=i+1∑n⟨vi,vj⟩xixj=f=1∑ki=1∑nj=i+1∑nvi,fvj,fxixj -
利用平方展开公式 ( a + b ) 2 = a 2 + b 2 + 2 a b (a+b)^2 = a^2 + b^2 + 2ab (a+b)2=a2+b2+2ab,可以将两两交互项转化为单个求和项:
∑ i = 1 n ∑ j = i + 1 n v i , f v j , f x i x j = 1 2 ( ( ∑ i = 1 n v i , f x i ) 2 − ∑ i = 1 n v i , f 2 x i 2 ) \sum_{i=1}^n \sum_{j=i+1}^n v_{i,f} v_{j,f} x_i x_j = \frac{1}{2} \left( \left( \sum_{i=1}^n v_{i,f} x_i \right)^2 - \sum_{i=1}^n v_{i,f}^2 x_i^2 \right) i=1∑nj=i+1∑nvi,fvj,fxixj=21 (i=1∑nvi,fxi)2−i=1∑nvi,f2xi2 -
将所有维度 f f f 的结果累加,得到最终公式。
1.3. 完整预测公式
将线性部分和优化后的交互部分结合起来,FM 的预测公式可以写为:
y
^
(
x
)
=
w
0
+
∑
i
=
1
n
w
i
x
i
+
1
2
∑
f
=
1
k
(
(
∑
i
=
1
n
v
i
,
f
x
i
)
2
−
∑
i
=
1
n
v
i
,
f
2
x
i
2
)
\hat{y}(\mathbf{x}) = w_0 + \sum_{i=1}^n w_i x_i + \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}^2 x_i^2 \right)
y^(x)=w0+i=1∑nwixi+21f=1∑k
(i=1∑nvi,fxi)2−i=1∑nvi,f2xi2
二、pointwise、pairwise、listwise原理和区别
2.1. Pointwise 方法
(1)原理
- Pointwise 方法将排序问题视为一个回归或分类问题。每个样本被单独处理,模型的目标是为每个样本预测一个独立的分数。
- 如果目标是回归问题,则预测值表示文档的相关性得分;如果是分类问题,则预测值表示文档是否相关。
(2)优点
- 简单直观,容易实现。
- 可以直接使用标准的回归或分类算法(如线性回归、逻辑回归等)。
(3)缺点
- 忽略了样本之间的相对关系,无法直接优化排序质量指标(如 NDCG、MAP)。对于排序任务来说,可能不够精确。
(4)适用场景
- 当样本之间相对顺序不重要时,或者排序目标可以通过简单的回归/分类来近似时。
2.2. Pairwise 方法
(1)原理
- Pairwise 方法关注样本对之间的相对顺序。模型的目标是比较两个样本的相关性得分,并确保相关性更高的样本获得更高的分数。
- 训练数据由样本对组成,标签表示两个样本之间的相对顺序(例如,1 表示第一个样本更重要,0 表示第二个样本更重要)。
(2)优点
- 能够直接建模样本之间的相对关系。更适合优化排序质量指标(如 NDCG、MAP),因为这些指标本质上依赖于样本对的相对顺序。
(3)缺点
- 需要构造大量的样本对,计算复杂度较高。在高维稀疏数据中可能会面临效率问题。
(4)适用场景
- 当需要优化排序质量指标时,或者样本之间的相对顺序非常重要时。
2.3. Listwise 方法
(1)原理
- Listwise 方法直接针对整个列表进行建模。模型的目标是为整个列表生成一个合理的排序,使得相关性高的样本排在前面。
- 训练数据由整个列表组成,标签通常是一个分布(如 Softmax 分布),表示每个样本在列表中的相对重要性。
(2)优点
- 最接近实际排序任务的需求,能够直接优化排序质量指标。
- 能够考虑整个列表的整体结构,而不仅仅是样本对的关系。
(3)缺点
- 实现复杂度较高,需要设计专门的损失函数(如 ListNet、ListMLE)。
- 对于大规模数据集,计算成本可能较高。
(4)适用场景
- 当排序任务需要考虑整个列表的整体结构时,或者需要直接优化排序质量指标时。
2.4. 三者的区别
特性 | Pointwise | Pairwise | Listwise |
---|---|---|---|
建模对象 | 单个样本 | 样本对 | 整个列表 |
目标 | 为每个样本预测独立的分数 | 确保相关性更高的样本获得更高分数 | 为整个列表生成合理排序 |
复杂度 | 最低 | 中等 | 最高 |
优化目标 | 回归或分类误差 | 样本对的相对顺序 | 排序质量指标(如 NDCG、MAP) |
适用场景 | 简单任务或初步实验 | 需要优化排序质量指标 | 需要考虑整个列表的整体结构 |
- Pointwise:简单易用,但忽略了样本之间的相对关系。
- Pairwise:关注样本对的相对顺序,适合优化排序质量指标。
- Listwise:直接针对整个列表建模,最适合真实的排序任务。
选择哪种方法取决于具体任务的需求和数据规模。如果需要快速实现,可以先尝试 Pointwise;如果排序质量指标很重要,可以选择 Pairwise 或 Listwise。
三、78. 子集(hot100_回溯_中等)
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
res = [[]]
for i in nums:
res = res + [[i] + num for num in res] # 神来之笔
return res