- 概
- Frequent Directions
- Frequent Directions over Slidding Windows
- 代码
Ghashami M., Liberty E., Phillips J. M. and Woodruff D. P. Frequent directions : Simple and deterministic matrix sketching. 2015.
Yin H., Wen D., Li J., Wei Z., Zhang X., Huang Z. and Li F. Optimal matrix sketching over sliding windows. VLDB, 2024.
概
通过魏老师的分享找了这些论文看了一下, 感觉之后可能会用到.
Frequent Directions
-
FD 的任务是, 希望维护一个 sketch matrix \(B \in \mathbb{R}^{\ell \times d}\) 使得 (\(A \in \mathbb{R}^{n \times d}\)),
\[\|A^T A - B^T B \|_2, \quad \|A - \pi_{B_k}(A) \|_F^2, \forall k < \ell \]这几个误差都尽可能小, 其中
\[\pi_{B_k}(A) = A V_kV_k^T, \]\(V_k\) 是 \(B = U\Lambda V^T\) 的 top-\(k\) 奇异值所对应的右奇异向量. 换言之, 我们通过维护 \(\ell \ll n\) 便保存了 \(A\) 中的大部分信息.
-
这个问题比较有意思的点在于, 如何处理, \(A\) 通过一行一行的形式得到, 然后我们动态地维护 \(B\) (否则这个问题就有一般方法了).
-
FD 启发自一个非常经典的问题: 频率估计问题.
- 假设, 我们有 \(A = \{a_1, \cdots, a_n\}\), 其中 \(a _i \in \{1, \ldots, d\}\). 我们会一个一个地接收到其中的元素, 问题是如何动态估计每个元素出现的频率:
\[\hat{f}_j \rightarrow f_j = |\{a_i \in A | a_i = j\}|. \]-
Misra-Gries 算法是频率估计的一个最优算法:
- 维护一个长度为 \(\ell\) 的 counters;
- 新来一个元素 \(a\): I) 若已经有 counter 在计数 \(a\) 则, 该 counter 加一; II) 倘若任有 counter 剩余 (即 counter 计数为 0), 则选择其一用于计数 \(a\); III) 倘若没有 counter 剩余, 则所有 counter 递减直到有其中一个 counter 为 0, 将此 counter 用于计数 \(a\).
-
容易发现, 由于每次'递减'操作减去的频率为'\(\ell\)', 所以最多有 \(n / \ell\) 次这种递减操作. 换言之:
\[0 \le f_j - \hat{f}_j \le n / \ell, \forall j. \]于是我们就得到了一个还算可以的频率估计, 实际上, 这个估计是最优的.
-
我们可以把这个推广到矩阵的形式. 假设 \(A \in \mathbb{R}^{n \times d}\) 的每一行为 \(\{e_j: j=1,2,\ldots, d\}\), 其中 \(e_j\) 表示第 \(j\) 个元素为 1, 其余元素为 0 的向量. 此时, 我们有:
\[f_j = \|A e_j\|^2. \]我们可以令 \(B\) 的第 \(j\) 行为: \(\hat{f}_j^{1/2} e_j\), 则有
\[\|Be_j\|^2 = \hat{f}_j, \]进一步地:
\[\|A^T A - B^TB \|_2 = \max_j |f_j - \hat{f}_j| \le \|A\|_F^2 / (\ell - k). \] -
FD 的最终算法就是有这样的一个'减'的操作:
-
具体操作就是, 新来一行 \(a\) 后, 拼接在最后, 然后进行奇异值分解, 然后所有的奇异值减去最小的奇异值, 此时
\[\sqrt{\Sigma^2 - \delta I_{\ell}} V^T \]的最后一行一定为 0. 这相当于我们空出来了一个 'counter'.
-
FD 可以进一步加速:
-
此时, 减去的是排中间的奇异值, 相当于我们会空出一半的 'counters'.
-
最后的 bound 请参考原文.
Frequent Directions over Slidding Windows
-
有些时候, 我们并不希望 \(B\) 去保存过去所有的信息, 而是最近的 N 行, 即逼近 \(A_W = A_{T-N, T} \in \mathbb{R}^{N \times d}\) 的信息 (\(T\) 表示当前的时刻).
-
其实, 这个算法也是启发自基于滑动窗口的频率估计问题:
- 给定阈值 \(\theta = N / \ell\);
- 按照普通的方式统计每个元素的频率, 此时时刻 \(T\) 来了一个新的元素 \(a\), 按照之前的 MG 的方式统计.
- 之后, 如果 \(a\) 的计数 \(\ge \theta\), 则将其归零, 并将 \((a, T)\) 加入一个列表 \(S\) 中.
- 检查 \(S\) 中的时间, 如果时间不在窗口内, 则舍弃.
-
最后, 我们可以以 \(S\) 中的记录以及 counters 中的记录作为频率, 其余不在其中的频率记为 \(0\). 容易发现,
- 对于 \(\hat{f}_j = 0\) 的:\[0 \le f_j - \hat{f}_j \le N / \ell. \]
- 对于 \(\hat{f}_j \not = 0\) 的, 由于舍弃的部分 (就是还在 counters 中的) 不会超过 \(N / \ell\), 所以也有\[0 \le f_j - \hat{f}_j \le N / \ell. \]
- 对于 \(\hat{f}_j = 0\) 的:
注: 我不太了解这个算法, 感觉应该是这样的.
- 所以 FD over lisding windows 的算法也是类似的:
-
和普通的 FD 主要有两点不同:
- 需要维护两个额外的列表 \(S, S'\), 用于维护超出阈值 \(\theta\) 的奇异向量;
- 每次经过普通的 FD 操作后, 如果首奇异值超过 \(\theta\), 对应的频谱就被剔除了.
-
此外, 每次更新还需要检查, 保存在 \(S, S'\) 中的奇异向量是否超过了窗口时间.
代码
[official-code]