这是笔者学习 Stanford cs 168 课程的一些学习笔记
lecture 2, 主要讲一个基于 hash 和独立试验思想,设计的一种数据结构 count min sketch,想法非常类似于 bloom filter,都是以牺牲准确率换空间和时间。

heavy hitter problem

Find majority element

先来看一个简单的在面试中经常会遇到的问题,找主要元素

问题如下: 一组数据流: a1,…,ana_1,\dots,a_na1​,…,an​, 存在一个元素 aia_iai​ 保证出现次数大于
n/2n/2n/2。 能否设计一个算法在 仅仅扫描一遍的情况下找到它。

这里有一个很 cute 的算法


current = -1
counter = 0for e in stream:if counter == 0:current = ecounter += 1elif e == current:counter += 1else counter -= 1return current

可以证明这个算法一定是正确的。

证明

数学归纳法

  1. 当 len(stream) = 1 的时候,一定是正确的
  2. 假设当 len(stream)<=n 的时候是正确的
  3. 当 len(stream) = n+1 的时候
    1. 如果 a1a_1a1​ 是ans,当 counter 第一次减少为0 的时候,流被分为两段,一段是走过的,另外一段是没有遍历过的,[s_1|counter=0|,s_2],设 l1,l2l_1,l_2l1​,l2​ 分别是两段的长度,显然,第一段中 cnt(a1)=s1/2cnt(a_1)=s_1 / 2cnt(a1​)=s1​/2 , 由于 a1a_1a1​ 是答案,它在整个序列中出现的次数大于 (n+1)/2(n+1)/2(n+1)/2 因此在 s2s_2s2​ 中,我们有 cnt(a1)&gt;n+12−s12=s22cnt(a_1) &gt; \frac{n+1}{2}-\frac{s_1}{2}=\frac{s_2}{2}cnt(a1​)>2n+1​−2s1​​=2s2​​ ,同时 len(s2)&lt;=nlen(s_2) &lt;=nlen(s2​)<=n 因此,由数学归纳法,再第二段中能正确找到答案。
    2. 如果 a2a_2a2​ 不是 ans,遍历第一段的时候,cnt(ans)&lt;s12cnt(ans) &lt; \frac{s_1}{2}cnt(ans)<2s1​​, 因此在第二段中 cnt(ans)&gt;s22cnt(ans)&gt;\frac{s_2}{2}cnt(ans)>2s2​​, 同理,根据数学归纳法,一定能找到答案

证毕

heavy hitter problem

这个问题是这样的,

给一个数据流 a1,…,ana_1,\dots,a_na1​,…,an​, 以及一个整数 kkk , 找出其中所有 出现次数(记作 frequency) 大于等于 nk\frac{n}{k}kn​ 的元素

朴素的做法是用一个 hash 表统计一下 每个元素出现的次数,然后再输出次数 ≥nk\ge \frac{n}{k}≥kn​ 的元素,这个算法能够解决这个问题,但是最大的问题是它需要的空间依赖于不同元素的个数,因此我们希望能找一个空间 亚线性(sublinear) 的算法,同时只需要遍历一次整个流,换句话说,希望如下代码能够解决这个问题

for e in stream:# code

对每个元素只看一次,同时保证空间需求 O(sizeOfAns)O(sizeOfAns)O(sizeOfAns)

impossible result

可以证明精确求解算法的亚线性辅助空间算法是不可能的。见 [1] 1.3, 因此我们希望找到一个近似做法

ϵ\epsilonϵ - heavy hitters problem

问题同上,不过我们仅仅希望最终找到的答案,满足如下需求:

  1. 每一个出现次数 ≥nk\ge \frac{n}{k}≥kn​ 的元素都在里面
  2. 每一个出现次数 ≥nk−ϵn\ge \frac{n}{k} - \epsilon n≥kn​−ϵn 的元素也可以在里面

我们允许使用的空间随着 O(1ϵ)O(\frac{1}{\epsilon})O(ϵ1​) 当 ϵ=0\epsilon = 0ϵ=0 就和原来的问题一样了。算法的空间使用情况为 O(1ϵ)=O(k)O(\frac{1}{\epsilon})=O(k)O(ϵ1​)=O(k)

下面就来介绍这篇博客的主角 count-min-sketch 频率统计利器

count min sketch

和 bloom filter 类似的hash 做法,结构如下:

其中 b&lt;&lt;nb &lt;&lt; nb<<n,支持两个操作:

add(x),将 x 的频率 +1
frq(x),统计 x 的频率

add(x):for i in range(l):cms[i][hash_i(x)] += 1frq(x):return min(cms[i][hash(x)]) for i in range(l)

很显然 frq(x)frq(x)frq(x) 一定会高估 cnt(x)cnt(x)cnt(x)(元素 xxx 的真实频率), 下面我们来分析一下会高估的概率是多少,同时我们希望 Pr⁡[min(cms[i][hashi(x)])≥cnt(x)]\Pr[min(cms[i][hash_i(x)]) \ge cnt(x)]Pr[min(cms[i][hashi​(x)])≥cnt(x)] 的概率足够小,

rigorous error analysis

先给出如下结论:

Pr⁡[min(cms[i][hashi(x)])≥cnt(x)]≤e−l\Pr[min(cms[i][hash_i(x)]) \ge cnt(x)] \le e^{-l}Pr[min(cms[i][hashi​(x)])≥cnt(x)]≤e−l

证明

定义:

fxf_xfx​ 元素 xxx 在stream 中的真实频率,这是一个常数
Zi=cms[i][hashi(x)]Z_i=cms[i][hash_i(x)]Zi​=cms[i][hashi​(x)]

假设

hash 函数是独立的,同时 Pr⁡[hash(x)=hash(y)∣y≠x]≤1b\Pr[hash(x)=hash(y)|y\ne x]\le \frac{1}{b}Pr[hash(x)=hash(y)∣y̸​=x]≤b1​

Zi=fx+∑hash(y)==hash(x),x≠yfyE[Zi]=fx+E[∑hash(y)==hash(x),x≠yfy]=fx+∑x≠yfyE[I(hash(y)=hash(x))]=fx+∑y≠xfyPr⁡[hash(y)=hash(x)]≤fx+nb\begin{aligned} Z_i&amp;=f_x+\sum_{hash(y)==hash(x),x\ne y} f_y\\ E[Z_i]&amp;=f_x + E[\sum_{hash(y)==hash(x),x\ne y} f_y]\\ &amp;= f_x+\sum_{x\ne y}f_yE[I(hash(y)=hash(x))]\\ &amp;= f_x+\sum_{y\ne x}f_y\Pr[hash(y)=hash(x)]\\ &amp;\le f_x + \frac{n}{b} \end{aligned} Zi​E[Zi​]​=fx​+hash(y)==hash(x),x̸​=y∑​fy​=fx​+E[hash(y)==hash(x),x̸​=y∑​fy​]=fx​+x̸​=y∑​fy​E[I(hash(y)=hash(x))]=fx​+y̸​=x∑​fy​Pr[hash(y)=hash(x)]≤fx​+bn​​

fix x 以及 row i令 b=eϵ,X=Zi−fxb=\frac{e}{\epsilon}, X = Z_i- f_xb=ϵe​,X=Zi​−fx​ 由于 E[X]≤nϵeE[X] \le \frac{n\epsilon}{e}E[X]≤enϵ​

由 markov’s inequality

Pr⁡[X&gt;cE[X]]≤1c\Pr[X &gt; cE[X]] \le \frac{1}{c}Pr[X>cE[X]]≤c1​

Pr⁡[Zi−fx≥nϵe∗e]=Pr⁡[Zi≥ϵn+fx]≤1ePr⁡[min(Zi)≥ϵn+fx]≤1el\begin{aligned} \Pr[Z_i-f_x\ge \frac{n\epsilon}{e}*e]&amp;=\Pr[Z_i\ge \epsilon n + f_x]\\ &amp;\le \frac{1}{e}\\ \Pr[min(Z_i)\ge \epsilon n + f_x] &amp;\le \frac{1}{e^l} \end{aligned} Pr[Zi​−fx​≥enϵ​∗e]Pr[min(Zi​)≥ϵn+fx​]​=Pr[Zi​≥ϵn+fx​]≤e1​≤el1​​

参数 trick

设错误概率为 σ\sigmaσ, 要达到这个概率,大概需要 l=ln⁡σ−1l = \ln \sigma^{-1}l=lnσ−1

同时,通常,b=eϵ=&gt;O(ϵ−1)=O(k)=ekb=\frac{e}{\epsilon} =&gt;^{O(\epsilon^{-1})=O(k)}=e kb=ϵe​=>O(ϵ−1)=O(k)=ek

作业中探讨了一种 Conservative Update 的 简单优化方式

conservative update

这是说,对于操作 add(x)

仅仅将 cms[i][hashi(x)]=min(cms[i][hashi(x)])cms[i][hash_i(x)] = min(cms[i][hash_i(x)])cms[i][hashi​(x)]=min(cms[i][hashi​(x)]) 的那些“格子” 更新,可以很容易的证明这不会低估 fxf_xfx​

扩展

很容易将操作扩展到 add(x,cnt) 上

code

这是一份我的作业中的代码 python 实现

这是一份开源代码 java 实现

reference

  1. CS168: The Modern Algorithmic Toolbox Lecture #2: Approximate Heavy Hitters and the Count-Min Sketch

版权声明

本作品为作者原创文章,采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议

作者: taotao

转载请保留此版权声明,并注明出处

Count Min Sketch: from Finding the Majority Element problem to heavy hitter problem,统计元素频率的利器相关推荐

  1. leetcode-169. Majority Element

    leetcode-169. Majority Element Given an array of size n, find the majority element. The majority ele ...

  2. leetcode 169. Majority Element

    Given an array of size n, find the majority element. The majority element is the element that appear ...

  3. LeetCode Majority Element

    Given an array of size n, find the majority element. The majority element is the element that appear ...

  4. 【LeetCode】169. Majority Element

    原题链接:https://leetcode.com/problems/majority-element/description/ 要求: Given an array of size n, find ...

  5. Leetcode - 169. Majority Element (多数投票问题)

    Given an array of size n, find the majority element. The majority element is the element that appear ...

  6. [LeetCode]: 169: Majority Element

    题目: Given an array of size n, find the majority element. The majority element is the element that ap ...

  7. [LeetCode]Majority Element

    题目描述: Given an array of size n, find the majority element. The majority element is the element that ...

  8. [LeetCode] 169. Majority Element 多数元素

    Given an array of size n, find the majority element. The majority element is the element that appear ...

  9. Majority Element(169) Majority Element II(229)

    寻找多数元素这一问题主要运用了:Majority Vote Alogrithm(最大投票算法) 1.Majority Element 1)description Given an array of s ...

最新文章

  1. [20160608]自治事务引起死锁.txt
  2. 19年NAACL纪实:自然语言处理的实用性见解 | CSDN博文精选
  3. xcode 学习笔记2:动态添加view
  4. 防火墙术语详解(一)
  5. 收集的伪静态中经常使用的一些参数解释,如[NC,L,QSA]等
  6. Swift NSDate的一个分类,把Mon Apr 04 19:45:37 +0800 2016这种格式的时间转换为2016-04-04 11:45:37 +0000
  7. twitter服务器部署系统
  8. 调试工具之UDP/TCP网络调试助手NetAssist
  9. editplus使用
  10. 王码86五笔使用技巧
  11. 跨语言词向量笔记2. 跨语言词向量表示简史
  12. LRC (Lyric) 字幕
  13. 当Activity设置为透明主题时,按Home键,Dialog闪烁的解决方法
  14. 自认为隐藏在计算机补码中的秘密(原来这么简单)
  15. #4.2混沌数学与混沌理论
  16. 一种近似AMP音频增益转dB的优化写法:20.0*log10(amp)
  17. B/S架构与C/S架构
  18. 风格迁移2020 —— 论文汇总——云盘分享
  19. Silverlight Tools
  20. 自制Kindle电子书转化的实用技巧

热门文章

  1. python写自动答题脚本_编写Python脚本拉取优学院答案
  2. MAUI 入门教程系列(5.XAML及页面介绍)
  3. 连续信号、离散信号、模拟信号与数字信号区别
  4. FPGA学习笔记_ROM核调用与调试
  5. python文件write原理,Python写入文件(write和writelines)详解
  6. 如何克隆服务器系统盘,如果把云服务器系统盘克隆
  7. swift 生命周期_iOS View的生命周期详解
  8. Charles工具使用-pc端
  9. 租车信息系统数据库设计(1)
  10. AT89C51单片机制作密码锁,真的很详细了