天天看点

《大数据算法》一3.3 寻找频繁元素的非随机算法

本节书摘来华章计算机《大数据算法》一书中的第3章 ,第3.3节,王宏志 编著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

上面讲的是一个简单的例子,接下来讲一个复杂的例子——频繁元素。

频繁元素指的是在数据流当中同一个元素出现多次,希望找到出现最频繁的元素。我们看一个例子:在数据流状态<32,12,14,32,7,12,32,7,6,12,4>中,当前最频繁的元素是32和12。这两个都是最频繁元素。

频繁元素问题

输入:流

《大数据算法》一3.3 寻找频繁元素的非随机算法

,隐式地定义了一个频率向量f=(f1,…,fn)。注意f1+…+fn=m。

输出:对于一个参数k,输出集合

《大数据算法》一3.3 寻找频繁元素的非随机算法

频繁元素问题有广泛的应用。在网络当中找到“elephant flow”、ip地址等,在搜索引擎中找到频繁查询,可以给这些最频繁的查询做一些优化。在应用当中求频繁元素时有一个假设,即zipf原则:典型的频率分布是高度偏斜的,只有少数频繁元素,大多数元素是非常不频繁的。这个假设是合法的,根据统计一般最多10%的元素占元素总个数的90%。

求精确解的方法很简单,可以对每一个单独元素设置一个计数器。当处理一个元素时,增加相应计数器。

例如求上述数据流中的频繁元素。

这样做确实能得到精确解。但缺点是很明显的,只要数据流里面有一个新元素,在内存当中就要保存这个元素和它的计数器。如果在整个数据流中不同数据的数量非常大,则它所需要的内存量也是非常大的。这意味着没有一个很具体的界限。最坏情况是需要维护n个计数器,数据的个数就是计数器的个数。但在现实当中可以提供的计数器个数k是远小于n的,因此,可以退而求其次,求近似解。

misra-gries算法是一个计算频繁元素的非随机化近似算法。求解思想为:对于接收到的元素x,如果已经为其分配计数器,则把相应计数器加1;如果没有相应计数器,但计数器个数少于k,就为其分配计数器,并设为1,意味着内存中还有空间;如果当前计数器的个数为k,说明内存已经满了,则把所有计数器减1,然后删除取值为0的计数器,这样内存就又有空间了,再依次处理下一个x。

考虑上面的例子,其中n=6,k=3,m=11。

这时候,如何根据计数器估计x出现的次数?最直接的办法是将内存里最后的数据定为x出现的次数,计数器在内存中将x返回,没有则返回0。很显然这种方法低估了计数问题,32出现了3次,但是最后只返回1次。

该算法的伪代码如算法3-2所示。算法3-2 求元素频率

初始化:a←;

算法精确性分析

定理3-2 算法3-2求得的元素a、频率估计fa和真实值fa之间的关系满足

《大数据算法》一3.3 寻找频繁元素的非随机算法

,其中m是数据流中所有元素出现的次数,m′是当前所有计数器之和。

证明 由于在计算过程中每个元素对应的计数器都可能减掉一些值,故显然

《大数据算法》一3.3 寻找频繁元素的非随机算法

下面通过分析删除最多的元素数分析fa与fa之差的上界。这二者的差距是由a所对应计数器的减少所引起的,出现一个减少计数器的步骤,相应计数器就要减少一次。因而问题转化为整个计算过程中a对应计数器减少的次数。

注意到在计算过程中,只有内存已经满了的时候,即已经有k个计数器的时候,才执行计数器减少步骤,而此时每个计数器减少了1,意味着共减少了k。而在出现减少的时候,应该往内存里放的元素并没有放到内存中,也就是说未计入输入元素的此次出现,因此,每次计数器减少的步骤相当于减少了k+1。整个数据流的元素总数是m,内存中保存的计数总数是m′,每一轮计数器减少步骤减少了k+1,那么应该有(m-m′)/(k+1)个计数器减少步骤,这也就意味着fa和fa最多相差(m-m′)/(k+1),即

《大数据算法》一3.3 寻找频繁元素的非随机算法

。■

由上述分析可见,当数据流中元素的总数远大于(m-m′)/(k+1)时,可得到频繁项的一个好的估计。而且错误的界限和k成反比,因为k越大估计值和真实值相差越小,即内存越大误差越小。

可以利用略图计算错误的界限,在内存中记录m、m′和k,然后,把内存里最后一个频繁元素再加上相差的值,就可以得到频繁元素真实值的一个上界,而内存中保存的估计值是频繁元素的一个下界。在频繁元素的真实值范围之内,估计就准确得多。该算法有效的原因源于zipf原则,就是说极少数元素出现的次数非常多,而大多数元素出现的次数非常少。

继续阅读