Loading [MathJax]/jax/output/PreviewHTML/jax.js

Misra-Gries频数估计算法

Misra-Gries算法最早由J. Misra和D. Gries在1982年提出 [1]。Misra-Gries算法可以看成是对Majority算法的一个扩展,可以对数据流中的频数提供相对误差为的估计,使用的空间复杂度为\mathrm{O}(1/\epsilon)

到了2000年左右,随着对数据流研究的再次兴起,[2] 和 [3] 又重新提出了类似的算法来用于频数估计。和原始论文不同,[2] 使用了哈希表而非平衡搜索树来保证频繁项。[3] 则通过多个链表来提高清理记录时的效率,使其在最坏情况下仍然可以保证O(1)的开销。

原始论文侧重于频繁项的估计,并没有对频数估计的误差进行分析。[4] 证明了当k = 1/\epsilon时,频数估计的相对误差为\epsilon。[5] 则表明Misra-Gries算法的估计误差仅取决于那些长尾的数据项。考虑到真实环境中的数据分布通常是倾斜的(如zipf分布),这个结论可以进一步提高收紧了估计误差的边界。

[5] 进一步扩展了Misra-Gries算法,使其可以支持记录有不同权重的场景。[6] 则优化了权重更新场景下更新和合并的效率。[5] 还提供了Misra-Gries算法的合并操作,而 [7] 则对合并的空间复杂度提供了更强的边界。[7] 同时也证明了Misra-Gries算法本质上是和SpaceSaving算法等价的。

算法实现

我们在Misra-Gries算法中维护了一组记录(e, f),其中e是数据流中的数据项,f是对e的频数估计。我们将这组记录记为\mathcal{D}

Misra-Gries算法的更新算法如下所示。当一个新元素i到达时,我们首先检查其是否已经在\mathcal{D}中存在。如果已经存在的话,那么我们直接将其对应的频数f_i加1;否则,我们在\mathcal{D}中添加一个新记录(e, 1)。如果\mathcal{D}中记录的数目超过了设定的阈值k,那么我们就需要对\mathcal{D}进行清理。我们去除当前\mathcal{D}中所有频数的最小值f_m,并将所有频数都减去f_m。如果一个数据项的频数变为0,那么我们就将其从\mathcal{D}中删除。

Misra-Gries算法更新操作
0

if i \in \mathcal{D}, then

1

f_i \gets f_i + 1

2

else

3

\mathcal{D} \gets \mathcal{D} \cup \{i\}

4

f_m = \min \{ f_e | e \in \mathcal{D} \}

5

​ for all j \in \mathcal{D}

6

f_j \gets f_j - f_m

7

​ if f_j = 0, then

8

\mathcal{D} \gets \mathcal{D} - \{j \}

9

​ end if

10

​ end for

11

end if

Misra-Gries算法的查询操作如下所示。当我们需要查询某个数据项的频数时,如果这个数据项存在于\mathcal{D}中,我们就返回其在\mathcal{D}中对应的频数;否则,我们直接返回0

Misra-Gries算法查询操作
0

if e \in \mathcal{D}

1

​ return f_e

2

else

3

​ return 0

4

end if

Misra-Gries算法也支持合并操作。在合并时,我们任意选择一个频繁集来作为基础,然后再将另一个频繁集中的记录逐个添加进去。Misra-Gries算法的合并操作如下所示:

Misra-Gries算法合并操作
0

\mathcal{D} \gets \mathcal{D}_a

1

for all i \in \mathcal{D}_b

2

​ if i \in \mathcal{D}, then

3

f_i \gets f_i + f_{i, b}

4

​ else

5

\mathcal{D} \gets \mathcal{D} \cup \{i \}

6

f_i \gets f_{i, b}

7

​ end if

8

​ if |\mathcal{D}| > k, then

9

f_m \gets \min \{ f_e | e \in \mathcal{D} \}

10

​ for all j \in \mathcal{D}

11

f_j \gets f_j - f_m

12

​ if f_j = 0, then

13

\mathcal{D} \gets \mathcal{D} - \{j\}

14

​ end if

15

​ end for

16

​ end if

17

end for

算法分析

定理. Misra-Gries算法对真实频数f提供的估计\hat{f}满足

0 \le f - \hat{f} \le \epsilon n

其中n为所有数据项的频数之和。此时所需的空间复杂度为\mathrm{O}(1/\epsilon)

证明. 令n为数据流中已经出现的记录数目,n’为保存在\mathcal{D}中所有频数的和。

我们对于频数估计的误差来自于我们对\mathcal{D}的清理操作。每次清理时,我们会将\mathcal{D}中的记录都减去一个相同的值。因此在整个计算过程中,受到影响的数据项数目一定大于等于k。因此,我们有

0 \le f - \hat{f} \le \frac{n - n’}{k} \le \frac{n}{k}

k = 1/\epsilon,则

0 \le f - \hat{f} \le \epsilon n

参考文献

[1] J. Misra, D. Gries. Finding repeated elements. In Science of Computer Programming 1982, vol. 2(2), pp. 143-152.

[2] E. Demaine et al. Frequency estimation of internet packet streams with limited space. In ESA 2002, pp. 348-360.

[3] R. Karp et al. A simple algorithm for finding frequent elements in streams and bags. In TODS 2003, vol. 28(1), pp. 51-55.

[4] P. Bose et al. Bounds for frequency estimation of packet streams. In SIROCCO 2003.

[5] R. Berinde et al. Space-optimal heavy hitters with strong error bounds. In PODS 2009, pp. 157-166.

[6] D. Anderson et al. A high-performance algorithm for identifying frequent items in data streams. In IMC 2017, pp. 268-282.

[7] P. Agarwal et al. Mergeable summaries. In PODS 2012, pp. 23-34.

作者

Xiaogang Shi (施晓罡)

发布于

2023-04-29

更新于

2023-05-24

许可协议

评论